Add SO APIs to Nokia VNFM adapter
[vfc/nfvo/driver/vnfm/svnfm.git] / nokiav2 / driver / src / main / java / org / onap / vfc / nfvo / driver / vnfm / svnfm / nokia / onap / so / SoV2LifecycleManager.java
1 /*
2  * Copyright 2016-2017, Nokia Corporation
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 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.onap.so;
17
18
19 import com.google.gson.Gson;
20 import com.google.gson.JsonElement;
21 import com.google.gson.JsonObject;
22 import com.nokia.cbam.lcm.v32.model.*;
23 import com.nokia.cbam.lcm.v32.model.VnfInfo;
24 import java.util.*;
25 import java.util.stream.Collectors;
26 import javax.servlet.http.HttpServletResponse;
27 import org.onap.aai.model.GenericVnf;
28 import org.onap.aai.model.VfModule;
29 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.api.IPackageProvider;
30 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.onap.direct.AAIExternalSystemInfoProvider;
31 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.onap.direct.AAIRestApiProvider;
32 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.onap.direct.SdcPackageProvider;
33 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.packagetransformer.OnapR2HeatPackageBuilder;
34 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.*;
35 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.notification.LifecycleChangeNotificationManager;
36 import org.onap.vnfmadapter.so.v2.model.*;
37 import org.onap.vnfmdriver.model.ExtVirtualLinkInfo;
38 import org.onap.vnfmdriver.model.*;
39 import org.onap.vnfmdriver.model.ScaleDirection;
40 import org.slf4j.Logger;
41 import org.springframework.beans.factory.annotation.Autowired;
42 import org.springframework.stereotype.Component;
43 import org.yaml.snakeyaml.Yaml;
44
45 import static java.util.Optional.empty;
46 import static java.util.stream.Collectors.toList;
47 import static java.util.stream.Collectors.toMap;
48
49 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.packagetransformer.OnapR2HeatPackageBuilder.*;
50 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.CbamUtils.*;
51 import static org.slf4j.LoggerFactory.getLogger;
52
53 /**
54  * Responsible for providing access to AAI APIs.
55  * Handles authentication and mandatory parameters.
56  */
57 @Component
58 public class SoV2LifecycleManager implements ISoV2LifecycleManager{
59     private static Logger logger = getLogger(SoV2LifecycleManager.class);
60     private final LifecycleManager lifecycleManager;
61     private final CbamRestApiProvider cbamRestApiProvider;
62     private final JobManager jobManager;
63     private final AAIRestApiProvider aaiRestApiProvider;
64     private final AAIExternalSystemInfoProvider aaiExternalSystemInfoProvider;
65     private final IPackageProvider packageProvider;
66
67     @Autowired
68     SoV2LifecycleManager(LifecycleManagerForSo lifecycleManager, CbamRestApiProviderForSo cbamRestApiProvider, JobManagerForSo jobManager, AAIRestApiProvider aaiRestApiProvider, AAIExternalSystemInfoProvider aaiExternalSystemInfoProvider, SdcPackageProvider packageProvider) {
69         this.lifecycleManager = lifecycleManager;
70         this.cbamRestApiProvider = cbamRestApiProvider;
71         this.jobManager = jobManager;
72         this.aaiRestApiProvider = aaiRestApiProvider;
73         this.aaiExternalSystemInfoProvider = aaiExternalSystemInfoProvider;
74         this.packageProvider = packageProvider;
75     }
76
77     @Override
78     public void createVnf(String vnfIdInAai, SoV2VnfCreateRequest request, HttpServletResponse httpResponse) {
79         GenericVnf genericVnf = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnf(vnfIdInAai, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
80         VnfmInfo vnfmInfo = locateVnfm(genericVnf);
81         Optional<com.nokia.cbam.lcm.v32.model.VnfInfo> matchingVnf = locateVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
82         if (request.isFailIfExists() != null && request.isFailIfExists()) {
83             if (matchingVnf.isPresent()) {
84                 throw buildFatalFailure(logger, "The VNF with " + vnfIdInAai + " identifier in A&AI can not be found in the VNFM");
85             }
86         }
87         String vnfIdInVnfm = null;
88         if (!matchingVnf.isPresent()) {
89             try {
90                 LifecycleManager.VnfCreationResult creationResult = lifecycleManager.create(vnfmInfo.getVnfmId(), genericVnf.getModelVersionId(), request.getName(), vnfIdInAai);
91                 vnfIdInVnfm = creationResult.getVnfInfo().getId();
92             } catch (Exception e) {
93                 logger.warn("Unable to create VNF with " + vnfIdInAai + " identifier in AAI", e);
94                 cleanUpVnf(vnfIdInAai, vnfmInfo, request, httpResponse);
95             }
96         } else {
97             vnfIdInVnfm = matchingVnf.get().getId();
98         }
99         try {
100             com.nokia.cbam.lcm.v32.model.VnfInfo vnfAfterCreation = cbamRestApiProvider.getCbamLcmApi(vnfmInfo.getVnfmId()).vnfsVnfInstanceIdGet(vnfIdInVnfm, CbamRestApiProvider.NOKIA_LCM_API_VERSION).blockingFirst();
101             updateModifiableAttributes(vnfmInfo.getVnfmId(), vnfAfterCreation, request.getInputs());
102             String vimId = request.getCloudOwner() + SEPARATOR + request.getRegionName();
103             List<ExtVirtualLinkInfo> externalVirtualLinks = addExtVirtualLinks(vimId, request.getInputs());
104             JsonObject operationAdditionalParameters = new JsonObject();
105             operationAdditionalParameters.addProperty("vimId", vimId);
106             AdditionalParameters additionalParameters = buildAdditionalParameters(request, genericVnf, vimId);
107             String etsiVnfdId = packageProvider.getCbamVnfdId(genericVnf.getModelVersionId());
108             if (!vnfAfterCreation.getInstantiationState().equals(InstantiationState.INSTANTIATED)) {
109                 lifecycleManager.instantiate(vnfmInfo.getVnfmId(), externalVirtualLinks, httpResponse, operationAdditionalParameters, additionalParameters, vnfIdInVnfm, genericVnf.getModelVersionId(), etsiVnfdId);
110                 logger.info("The VNF in VNFM with " + vnfIdInAai + " identifier in A&AI and " + vnfIdInVnfm + " identifier in VNFM has been instantiated");
111             } else {
112                 logger.info("The VNF in VNFM with " + vnfIdInAai + " identifier in A&AI and " + vnfIdInVnfm + " identifier in VNFM is already instantiated");
113             }
114         } catch (Exception e) {
115             logger.warn("The VNF in VNFM with " + vnfIdInAai + " identifier in A&AI and " + vnfIdInVnfm + " identifier in VNFM can not be instantiated", e);
116             cleanUpVnf(vnfIdInAai, vnfmInfo, request, httpResponse);
117         }
118     }
119
120     @Override
121     public SoV2VnfQueryResponse queryVnf(String vnfIdInAai, SoV2VnfQueryRequest request, HttpServletResponse httpResponse) {
122         GenericVnf genericVnf = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnf(vnfIdInAai, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
123         VnfmInfo vnfmInfo = locateVnfm(genericVnf);
124         Optional<com.nokia.cbam.lcm.v32.model.VnfInfo> matchingVnf = locateVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
125         SoV2VnfQueryResponse response = new SoV2VnfQueryResponse();
126         response.setStatus(getStatus(vnfmInfo, matchingVnf));
127         return response;
128     }
129
130     private SoVnfStatus getStatus(VnfmInfo vnfmInfo, Optional<VnfInfo> matchingVnf) {
131         if(matchingVnf.isPresent()){
132             OperationExecution lastOperation = findLastOperation(vnfmInfo.getVnfmId(), matchingVnf.get().getId());
133             if(lastOperation.getStatus().equals(OperationStatus.FINISHED)){
134                 return SoVnfStatus.ACTIVE;
135             }
136             else if(lastOperation.getStatus().equals(OperationStatus.FAILED)){
137                 return SoVnfStatus.FAILED;
138             }
139             else {
140                 return SoVnfStatus.UNKNOWN;
141             }
142         }
143         else{
144             return SoVnfStatus.NOTFOUND;
145         }
146     }
147
148     private void cleanUpVnf(String vnfIdInAai, VnfmInfo vnfmInfo, SoV2VnfCreateRequest request, HttpServletResponse httpServletResponse) {
149         if(request.isDeleteUponFailure() != null && request.isDeleteUponFailure()) {
150             logger.info("Cleaning up the VNF in VNFM with " + vnfIdInAai + " identifier in A&AI");
151             SoV2VnfDeleteRequest deleteRequest = new SoV2VnfDeleteRequest();
152             deleteRequest.setMsoRequest(request.getMsoRequest());
153             delete(vnfIdInAai, deleteRequest, httpServletResponse);
154         }
155     }
156
157     private AdditionalParameters buildAdditionalParameters(SoV2VnfCreateRequest request, GenericVnf genericVnf, String vimId) {
158         AdditionalParameters additionalParameters = new AdditionalParameters();
159         buildZones(additionalParameters, vimId, request.getInputs());
160         JsonObject cbamVnfd = new Gson().toJsonTree(new Yaml().load(packageProvider.getCbamVnfdId(genericVnf.getModelVersionId()))).getAsJsonObject();
161         VduMappings vduMappings = getVduToVirtualComputeDescriptoId(cbamVnfd);
162         buildFlavours(vimId, additionalParameters, request.getInputs(), vduMappings.vduIdToVirtualComputeId);
163         buildExtenstions(request, additionalParameters);
164         buildImages(vimId, vduMappings, additionalParameters, request.getInputs());
165         setInstantiationLevel(cbamVnfd, additionalParameters);
166         return additionalParameters;
167     }
168
169     private List<ExtVirtualLinkInfo> addExtVirtualLinks(String vimId, SoInput inputs) {
170         List<ExtVirtualLinkInfo> externalVirtualLinks = new ArrayList<>();
171         for (Map.Entry<String, String> netInput : filterInput(inputs, ".*" + NET_ID)) {
172             ExtVirtualLinkInfo vl = new ExtVirtualLinkInfo();
173             String ecpId = netInput.getKey().replaceAll(NET_ID + "$", "");
174             vl.setVim(new ExtVirtualLinkInfoVim());
175             vl.getVim().setVimid(vimId);
176             vl.setResourceId(netInput.getValue());
177             vl.setCpdId(ecpId);
178             externalVirtualLinks.add(vl);
179         }
180         return externalVirtualLinks;
181     }
182
183     private void setInstantiationLevel(JsonObject cbamVnfd, AdditionalParameters additionalParameters) {
184         JsonObject topologyTemplate = child(cbamVnfd, "topology_template");
185         JsonObject substitutionMappings = child(topologyTemplate, "substitution_mappings");
186         JsonObject deploymentFlavor = child(child(substitutionMappings, "capabilities"), "deployment_flavour");
187         String defaultInstantiationLevel = childElement(child(deploymentFlavor, "properties"), "default_instantiation_level_id").getAsString();
188         additionalParameters.setInstantiationLevel(defaultInstantiationLevel);
189     }
190
191     private void buildImages(String vimId, VduMappings vduMappings, AdditionalParameters additionalParameters, SoInput inputs) {
192         for (Map.Entry<String, String> imageInput : filterInput(inputs, ".*" + IMAGE_NAME)) {
193             String vduName = imageInput.getKey().replace(IMAGE_NAME, "");
194             if (vduMappings.vduIdToVirtualSoftwareId.containsKey(vduName)) {
195                 VimSoftwareImage image = new VimSoftwareImage();
196                 image.setVimId(vimId);
197                 image.setResourceId(imageInput.getKey());
198                 image.setVnfdSoftwareImageId(vduMappings.vduIdToVirtualSoftwareId.get(vduName));
199                 additionalParameters.getSoftwareImages().add(image);
200             }
201         }
202     }
203
204     private void buildExtenstions(SoV2VnfCreateRequest request, AdditionalParameters additionalParameters) {
205         for (Map.Entry<String, String> extenstion : filterInput(request.getInputs(), ".*" + ETSI_MODIFIABLE_ATTRIBUTES_EXTENSTION)) {
206             VnfProperty property = new VnfProperty();
207             property.setName(extenstion.getKey().replace(ETSI_MODIFIABLE_ATTRIBUTES_EXTENSTION, ""));
208             property.setValue(extenstion.getValue());
209             additionalParameters.getExtensions().add(property);
210         }
211     }
212
213     private static class VduMappings {
214         HashMap<String, String> vduIdToVirtualComputeId = new HashMap<>();
215         HashMap<String, String> vduIdToVirtualSoftwareId = new HashMap<>();
216     }
217
218     private VduMappings getVduToVirtualComputeDescriptoId(JsonObject root) {
219         VduMappings vduMappings = new VduMappings();
220         JsonObject topologyTemplate = child(root, "topology_template");
221         JsonObject nodeTemplates = child(topologyTemplate, "node_templates");
222         for (Map.Entry<String, JsonElement> vdu : OnapR2HeatPackageBuilder.filterType(nodeTemplates, "tosca.nodes.nfv.VDU")) {
223             boolean found = false;
224             for (JsonElement requirement : childElement(vdu.getValue().getAsJsonObject(), "requirements").getAsJsonArray()) {
225                 if (requirement.getAsJsonObject().has("virtual_compute")) {
226                     vduMappings.vduIdToVirtualComputeId.put(vdu.getKey(), requirement.getAsJsonObject().get("virtual_compute").getAsString());
227                     found = true;
228                 }
229                 if (requirement.getAsJsonObject().has("sw_image")) {
230                     vduMappings.vduIdToVirtualSoftwareId.put(vdu.getKey(), requirement.getAsJsonObject().get("sw_image").getAsString());
231                 }
232             }
233             if (!found) {
234                 throw buildFatalFailure(logger, "Unable to find virtualComputeDescriptor for " + vdu.getKey() + " identifier");
235             }
236         }
237         return vduMappings;
238     }
239
240     private void buildFlavours(String vimId, AdditionalParameters additionalParameters, SoInput inputs, Map<String, String> vduToVirtualComputeDescriptoId) {
241         for (Map.Entry<String, String> input : filterInput(inputs, ".*_flavor_name")) {
242             String vduName = input.getKey().replaceAll("_flavor_name$", "");
243             VimComputeResourceFlavour flavor = new VimComputeResourceFlavour();
244             flavor.setVimId(vimId);
245             flavor.setVnfdVirtualComputeDescId(vduToVirtualComputeDescriptoId.get(vduName));
246             flavor.setResourceId(input.getValue());
247             additionalParameters.getComputeResourceFlavours().add(flavor);
248         }
249     }
250
251     private Set<Map.Entry<String, String>> filterInput(SoInput input, String pattern) {
252         return input.entrySet().stream().filter(i -> i.getKey().matches(pattern)).collect(Collectors.toSet());
253     }
254
255     private void buildZones(AdditionalParameters additionalParameters, String vimId, SoInput inputs) {
256         for (Map.Entry<String, String> input : filterInput(inputs, "availability_zone_[0-9]*")) {
257             ZoneInfo zone = new ZoneInfo();
258             zone.setId(input.getKey());
259             zone.setResourceId(input.getValue());
260             zone.setVimId(vimId);
261             additionalParameters.getZones().add(zone);
262         }
263     }
264
265     private OperationExecution findLastOperation(String vnfmId, String vnfIdInVnfm) {
266         List<OperationExecution> operationExecutions = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdOperationExecutionsGet(vnfIdInVnfm, CbamRestApiProvider.NOKIA_LCM_API_VERSION).blockingFirst();
267         return LifecycleChangeNotificationManager.NEWEST_OPERATIONS_FIRST.sortedCopy(operationExecutions).get(0);
268     }
269
270     @Override
271     public void delete(String vnfIdInAai, SoV2VnfDeleteRequest request, HttpServletResponse httpServletResponse) {
272         GenericVnf genericVnf = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnf(vnfIdInAai, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
273         VnfmInfo vnfmInfo = locateVnfm(genericVnf);
274         Optional<com.nokia.cbam.lcm.v32.model.VnfInfo> matchingVnf = locateVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
275         if (matchingVnf.isPresent()) {
276             VnfTerminateRequest terminateRequest = new VnfTerminateRequest();
277             terminateRequest.setTerminationType(VnfTerminationType.GRACEFUL);
278             terminateRequest.setGracefulTerminationTimeout(Long.valueOf(60 * 60 * 1000L).toString());
279             jobManager.waitForJobToFinish(lifecycleManager.terminateAndDelete(vnfmInfo.getVnfmId(), matchingVnf.get().getId(), terminateRequest, httpServletResponse));
280         }
281     }
282
283     @Override
284     public void rollback(String vnfIdInAai, SoV2RollbackVnfUpdate rollback, HttpServletResponse httpServletResponse) {
285         GenericVnf genericVnf = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnf(vnfIdInAai, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
286         VnfmInfo vnfmInfo = locateVnfm(genericVnf);
287         VnfInfo vnfInfo = expectVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
288         ModifyVnfInfoRequest request= new ModifyVnfInfoRequest();
289         request.setExtensions(buildExtension(rollback.getOriginalVnfProperties()));
290         lifecycleManager.executeModifyVnfInfo(vnfmInfo.getVnfmId(), vnfInfo.getId(), request);
291     }
292
293     @Override
294     public void createVfModule(String vnfIdInAai, String vfModuleId, SoV2VfModuleCreateRequest request, HttpServletResponse httpResponse) {
295         GenericVnf genericVnf = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnf(vnfIdInAai, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
296         VnfmInfo vnfmInfo = locateVnfm(genericVnf);
297         VnfInfo vnfInfo = expectVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
298         healVnfIfRequired(vnfIdInAai, httpResponse, vnfmInfo, vnfInfo);
299         executeScale(request.getScalingAspectId(), httpResponse, genericVnf, vnfmInfo, vnfInfo);
300     }
301
302     @Override
303     public void deleteVfModule(String vnfIdInAai, String vfModuleId, SoV2VnfDeleteRequest request, HttpServletResponse httpResponse) {
304         GenericVnf genericVnf = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnf(vnfIdInAai, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
305         VnfmInfo vnfmInfo = locateVnfm(genericVnf);
306         VnfInfo vnfInfo = expectVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
307         VfModule vfModule = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnfVfModulesVfModule(genericVnf.getVnfId(), vfModuleId, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
308         String aspectId = vfModule.getHeatStackId();
309         executeScale(aspectId, httpResponse, genericVnf, vnfmInfo, vnfInfo);
310         healVnfIfRequired(vnfIdInAai, httpResponse, vnfmInfo, vnfInfo);
311     }
312
313     @Override
314     public SoV2VnfUpdateResponse updateVfModule(String vnfIdInAai, String vfModuleId, SoV2VnfUpdateRequest request, HttpServletResponse httpResponse) {
315         return updateVnf(vnfIdInAai, request, httpResponse);
316     }
317
318     private void executeScale(String aspectId, HttpServletResponse httpResponse, GenericVnf genericVnf, VnfmInfo vnfmInfo, VnfInfo vnfInfo) {
319         ScaleInfo scaleInfo = vnfInfo.getInstantiatedVnfInfo().getScaleStatus().stream().filter(s -> s.getAspect().equals(aspectId)).findFirst().get();
320         long expectedStepCount = genericVnf.getVfModules().stream().filter(m -> m.getHeatStackId().equals(aspectId)).count();
321         if(expectedStepCount != scaleInfo.getScaleLevel().longValue()){
322             VnfScaleRequest scaleRequest = new VnfScaleRequest();
323             scaleRequest.setAspectId(aspectId);
324             scaleRequest.setType(expectedStepCount > scaleInfo.getScaleLevel().longValue() ? ScaleDirection.OUT : ScaleDirection.IN);
325             scaleRequest.setNumberOfSteps(Long.valueOf(Math.abs(expectedStepCount - scaleInfo.getScaleLevel().longValue())).toString());
326             JobInfo jobInfo = lifecycleManager.scaleVnf(vnfmInfo.getVnfmId(), vnfInfo.getId(), scaleRequest, httpResponse);
327             jobManager.waitForJobToFinish(jobInfo);
328         }
329     }
330
331     private void healVnfIfRequired(String vnfIdInAai, HttpServletResponse httpResponse, VnfmInfo vnfmInfo, VnfInfo vnfInfo) {
332         OperationExecution lastOperation = findLastOperation(vnfmInfo.getVnfmId(), vnfIdInAai);
333         if(lastOperation.getStatus().equals(OperationStatus.FAILED)){
334             VnfHealRequest healRequest = new VnfHealRequest();
335             healRequest.setAffectedvm(new VnfHealRequestAffectedvm());
336             healRequest.setAction("reboot");
337             JobInfo jobInfo = lifecycleManager.healVnf(vnfmInfo.getVnfmId(), vnfInfo.getId(), healRequest, empty(), httpResponse);
338             jobManager.waitForJobToFinish(jobInfo);
339         }
340     }
341
342     @Override
343     public SoV2VnfUpdateResponse updateVnf(String vnfIdInAai, SoV2VnfUpdateRequest request, HttpServletResponse httpResponse) {
344         GenericVnf genericVnf = aaiRestApiProvider.getNetworkApi().getNetworkGenericVnfsGenericVnf(vnfIdInAai, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null).blockingFirst();
345         VnfmInfo vnfmInfo = locateVnfm(genericVnf);
346         Optional<com.nokia.cbam.lcm.v32.model.VnfInfo> matchingVnf = locateVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
347         Map<String, String> specifiedExtensions = collecSpecifiedExtensions(request.getInputs());
348         SoV2VnfUpdateResponse response = new SoV2VnfUpdateResponse();
349         Map<String, String> existingProperties = matchingVnf.get().getExtensions().stream().filter(p -> specifiedExtensions.containsKey(p.getName())).collect(Collectors.toMap(vnfProperty -> vnfProperty.getName(), vnfProperty -> vnfProperty.getValue().toString()));
350         response.setOriginalVnfProperties(new OriginalVnfProperties());
351         response.getOriginalVnfProperties().putAll(existingProperties);
352         if(matchingVnf.isPresent()){
353             try{
354                 ModifyVnfInfoRequest modifyRequest = new ModifyVnfInfoRequest();
355                 modifyRequest.setExtensions(buildExtension(specifiedExtensions));
356                 lifecycleManager.executeModifyVnfInfo(vnfmInfo.getVnfmId(), matchingVnf.get().getId(), modifyRequest);
357                 response.setSuccessful(true);
358             }
359             catch (Exception e){
360                 response.setSuccessful(false);
361             }
362             return response;
363         }
364         else{
365             throw buildFatalFailure(logger, "No VNF with " + vnfIdInAai + " identifier in A&AI exists in the VNFM");
366         }
367     }
368
369     private List<VnfProperty> buildExtension(Map<String, String> specifiedExtensions) {
370         return specifiedExtensions.entrySet().stream().map(e -> {
371             VnfProperty p = new VnfProperty();
372             p.setName(e.getKey());
373             p.setValue(e.getValue());
374             return p;
375         }).collect(toList());
376     }
377
378     private void updateModifiableAttributes(String vnfmId, com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo, SoInput inputs) {
379         ModifyVnfInfoRequest request = new ModifyVnfInfoRequest();
380         request.setExtensions(new ArrayList<>());
381         Map<String, String> specifedExtensions = collecSpecifiedExtensions(inputs);
382         for (Map.Entry<String, String> specifiedExtension : specifedExtensions.entrySet()) {
383             Optional<VnfProperty> exactProperty = vnfInfo.getExtensions().stream().filter(p -> p.getName().equals(specifiedExtension.getKey()) && p.getValue().equals(specifiedExtension.getValue())).findFirst();
384             if (!exactProperty.isPresent()) {
385                 VnfProperty onapCsarIdProperty = new VnfProperty();
386                 onapCsarIdProperty.setName(specifiedExtension.getKey());
387                 onapCsarIdProperty.setValue(specifiedExtension.getValue());
388                 request.getExtensions().add(onapCsarIdProperty);
389             }
390         }
391         if (!request.getExtensions().isEmpty()) {
392             lifecycleManager.executeModifyVnfInfo(vnfmId, vnfInfo.getId(), request);
393         }
394     }
395
396     private Map<String, String> collecSpecifiedExtensions(SoInput inputs) {
397         return inputs.entrySet().stream().filter(i -> i.getKey().startsWith("etsi.modifiableAttribute.")).collect(toMap(i -> i.getKey().replace("etsi.modifiableAttribute.", ""), i -> i.getValue()));
398     }
399
400     private Optional<com.nokia.cbam.lcm.v32.model.VnfInfo> locateVnfBasedOnAaiVnfId(String vnfIdInAai, VnfmInfo vnfmInfo) {
401         return cbamRestApiProvider.getCbamLcmApi(vnfmInfo.getVnfmId()).vnfsGet(CbamRestApiProvider.NOKIA_LCM_API_VERSION).blockingFirst().stream().filter(vnf -> vnf.getDescription().equals(vnfIdInAai)).findFirst();
402     }
403
404     private com.nokia.cbam.lcm.v32.model.VnfInfo expectVnfBasedOnAaiVnfId(String vnfIdInAai, VnfmInfo vnfmInfo) {
405         Optional<VnfInfo> vnfInfo = locateVnfBasedOnAaiVnfId(vnfIdInAai, vnfmInfo);
406         if(!vnfInfo.isPresent()){
407             throw buildFatalFailure(logger, "Unable to locate VNF with " + vnfIdInAai + " A&AI identifier in VNFM");
408         }
409         return vnfInfo.get();
410     }
411
412     private VnfmInfo locateVnfm(GenericVnf vnf) {
413         for (String vnfmId : aaiExternalSystemInfoProvider.getVnfms()) {
414             VnfmInfo vnfmInfo = aaiExternalSystemInfoProvider.queryVnfmInfoFromSource(vnfmId);
415             if (vnfmInfo.getType().equals(vnf.getNfType())) {
416                 return vnfmInfo;
417             }
418         }
419         throw buildFatalFailure(logger, "Unable to locate a VNFM for VNF with " + vnf.getVnfId() + " identifier with " + vnf.getNfType() + " type");
420     }
421 }