Fix extenstion handling
[vfc/nfvo/driver/vnfm/svnfm.git] / nokiav2 / driver / src / main / java / org / onap / vfc / nfvo / driver / vnfm / svnfm / nokia / vnfm / LifecycleManager.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
17 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm;
18
19
20 import com.google.common.base.Joiner;
21 import com.google.gson.Gson;
22 import com.google.gson.JsonElement;
23 import com.google.gson.JsonObject;
24 import com.google.gson.JsonParser;
25 import com.nokia.cbam.catalog.v1.model.CatalogAdapterVnfpackage;
26 import com.nokia.cbam.lcm.v32.model.*;
27 import com.nokia.cbam.lcm.v32.model.ScaleDirection;
28 import java.util.*;
29 import java.util.concurrent.ExecutorService;
30 import java.util.concurrent.Executors;
31 import javax.servlet.http.HttpServletResponse;
32 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.api.IGrantManager;
33 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.api.VimInfoProvider;
34 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.StoreLoader;
35 import org.onap.vnfmdriver.model.ExtVirtualLinkInfo;
36 import org.onap.vnfmdriver.model.*;
37 import org.onap.vnfmdriver.model.VimInfo;
38 import org.onap.vnfmdriver.model.VnfInfo;
39 import org.slf4j.Logger;
40 import org.yaml.snakeyaml.Yaml;
41
42 import static java.lang.Integer.parseInt;
43 import static java.nio.charset.StandardCharsets.UTF_8;
44
45 import static com.google.common.base.Splitter.on;
46 import static com.google.common.collect.Iterables.find;
47 import static com.google.common.collect.Iterables.transform;
48 import static com.google.common.collect.Lists.newArrayList;
49 import static com.google.common.collect.Ordering.natural;
50 import static com.google.common.collect.Sets.newHashSet;
51 import static com.nokia.cbam.lcm.v32.model.InstantiationState.INSTANTIATED;
52 import static com.nokia.cbam.lcm.v32.model.OperationStatus.FINISHED;
53 import static com.nokia.cbam.lcm.v32.model.OperationType.INSTANTIATE;
54 import static com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum.*;
55 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.CbamUtils.*;
56 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.SystemFunctions.systemFunctions;
57 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.CbamRestApiProvider.NOKIA_LCM_API_VERSION;
58 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.notification.LifecycleChangeNotificationManager.NEWEST_OPERATIONS_FIRST;
59 import static org.slf4j.LoggerFactory.getLogger;
60 import static org.springframework.util.StringUtils.isEmpty;
61
62 /**
63  * Responsible for executing lifecycle operation on the VNF
64  */
65 public class LifecycleManager {
66     public static final String ONAP_CSAR_ID = "onapCsarId";
67     public static final long OPERATION_STATUS_POLLING_INTERVAL_IN_MS = 5000L;
68     /**
69      * The key of the CBAM VNF extension for the identifier of the VNFM in ONAP
70      */
71     public static final String EXTERNAL_VNFM_ID = "externalVnfmId";
72     public static final String SCALE_OPERATION_NAME = "scale";
73     public static final String ETSI_CONFIG = "etsi_config";
74     public static final String PROPERTIES = "properties";
75     private static Logger logger = getLogger(LifecycleManager.class);
76     private final CatalogManager catalogManager;
77     private final IGrantManager grantManager;
78     private final JobManager jobManager;
79     private final ILifecycleChangeNotificationManager notificationManager;
80     private final CbamRestApiProvider cbamRestApiProvider;
81     private final VimInfoProvider vimInfoProvider;
82
83     /**
84      * Runs asynchronous operations in the background
85      */
86     private ExecutorService executorService = Executors.newCachedThreadPool();
87
88     LifecycleManager(CatalogManager catalogManager, IGrantManager grantManager, CbamRestApiProvider restApiProvider, VimInfoProvider vimInfoProvider, JobManager jobManager, ILifecycleChangeNotificationManager notificationManager) {
89         this.vimInfoProvider = vimInfoProvider;
90         this.grantManager = grantManager;
91         this.cbamRestApiProvider = restApiProvider;
92         this.jobManager = jobManager;
93         this.notificationManager = notificationManager;
94         this.catalogManager = catalogManager;
95     }
96
97     /**
98      * @param vimId the VIM identifier
99      * @return the name of the region
100      */
101     public static String getRegionName(String vimId) {
102         return newArrayList(on(SEPARATOR).split(vimId)).get(1);
103     }
104
105     /**
106      * @param vimId the VIM identifier
107      * @return the owner of the cloud
108      */
109     public static String getCloudOwner(String vimId) {
110         return newArrayList(on(SEPARATOR).split(vimId)).get(0);
111     }
112
113     private static OperationExecution findLastInstantiation(List<OperationExecution> operationExecutions) {
114         return find(NEWEST_OPERATIONS_FIRST.sortedCopy(operationExecutions), op -> INSTANTIATE.equals(op.getOperationType()));
115     }
116
117     public static String getVnfdIdFromModifyableAttributes(com.nokia.cbam.lcm.v32.model.VnfInfo vnf) {
118         return find(vnf.getExtensions(), p -> p.getName().equals(ONAP_CSAR_ID)).getValue().toString();
119     }
120
121     /**
122      * Create the VNF. It consists of the following steps
123      * <ul>
124      * <li>upload the VNF package to CBAM package (if not already there)</li>
125      * <li>create the VNF on CBAM</li>
126      * <li>modify attributes of the VNF (add onapCsarId field)</li>
127      * </ul>
128      * The rollback of the failed operation is not implemented
129      * <ul>
130      * <li>delete the VNF if error occurs before instantiation</li>
131      * <li>terminateVnf & delete VNF if error occurs after instantiation</li>
132      * </ul>
133      *
134      * @param vnfmId      the identifier of the VNFM
135      * @param csarId      the identifier of the VNF package
136      * @param vnfName     the name of the VNF
137      * @param description the description of the VNF
138      * @return the VNF creation result
139      */
140     public VnfCreationResult create(String vnfmId, String csarId, String vnfName, String description) {
141         logOperationInput("not yet specified", "creation", csarId);
142         try {
143             CatalogAdapterVnfpackage cbamPackage = catalogManager.preparePackageInCbam(vnfmId, csarId);
144             CreateVnfRequest vnfCreateRequest = new CreateVnfRequest();
145             vnfCreateRequest.setVnfdId(cbamPackage.getVnfdId());
146             vnfCreateRequest.setName(vnfName);
147             vnfCreateRequest.setDescription(description);
148             com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsPost(vnfCreateRequest, NOKIA_LCM_API_VERSION).blockingFirst();
149             addVnfdIdToVnfModifyableAttributeExtensions(vnfmId, vnfInfo.getId(), csarId);
150             return new VnfCreationResult(vnfInfo, cbamPackage.getVnfdId());
151         } catch (Exception e) {
152             throw buildFatalFailure(logger, "Unable to create the VNF", e);
153         }
154     }
155
156     private void logOperationInput(String vnfId, String operationName, Object payload) {
157         if (logger.isInfoEnabled()) {
158             logger.info("Starting {} operation on VNF with {} identifier with {} parameter", operationName, vnfId, new Gson().toJson(payload));
159         }
160     }
161
162     /**
163      * Instantiate the VNF
164      *
165      * @param vnfmId                        the identifier of the VNFM
166      * @param externalVirtualLinks          the external virtual links of the VNF
167      * @param httpResponse                  the HTTP response that corresponds to the VNF instantiation request
168      * @param additionalParameters          additional parameters
169      * @param vnfId                         the identifier of the VNF
170      * @param vnfmVnfdId                    the identifier of the VNF package in CBAM
171      * @param operationAdditionalParameters the additional parameters of the operation
172      * @param onapVnfdId                    the identifier of the VNFD in the VNFM
173      * @return the instantiation response
174      */
175     @SuppressWarnings("squid:S00107") //wrapping them into an object makes the code less readable
176     public VnfInstantiateResponse instantiate(String vnfmId, List<ExtVirtualLinkInfo> externalVirtualLinks, HttpServletResponse httpResponse, Object operationAdditionalParameters, AdditionalParameters additionalParameters, String vnfId, String onapVnfdId, String vnfmVnfdId) {
177         logOperationInput(vnfId, "instantiation", additionalParameters);
178         validateVimType(additionalParameters.getVimType());
179         VnfInstantiateResponse response = new VnfInstantiateResponse();
180         response.setVnfInstanceId(vnfId);
181         String vimId = getVimId(operationAdditionalParameters);
182         JobInfo spawnJob = scheduleExecution(vnfId, httpResponse, "instantiate", jobInfo ->
183                 instantiateVnf(vnfmId, externalVirtualLinks, additionalParameters, onapVnfdId, vnfmVnfdId, vnfId, vimId, jobInfo)
184         );
185         response.setJobId(spawnJob.getJobId());
186         return response;
187     }
188
189     /**
190      * Instantiate (VF-C terminology) the VNF. It consists of the following steps
191      * <ul>
192      * <li>upload the VNF package to CBAM package (if not already there)</li>
193      * <li>create the VNF on CBAM</li>
194      * <li>modify attributes of the VNF (add onapCsarId field)</li>
195      * <li>asynchronously</li>
196      * <li>request grant from VF-C</li>
197      * <li>instantiate VNF on CBAM</li>
198      * <li>return VNF & job id (after create VNF on CBAM)</li>
199      * <li></li>
200      * </ul>
201      * The rollback of the failed operation is not implemented
202      * <ul>
203      * <li>delete the VNF if error occurs before instantiation</li>
204      * <li>terminateVnf & delete VNf if error occurs after instantiation</li>
205      * </ul>
206      *
207      * @param vnfmId       the identifier of the VNFM
208      * @param request      the instantiation request
209      * @param httpResponse the HTTP response
210      * @return the instantiation response
211      */
212     public VnfInstantiateResponse createAndInstantiate(String vnfmId, VnfInstantiateRequest request, HttpServletResponse httpResponse) {
213         AdditionalParameters additionalParameters = convertInstantiationAdditionalParams(request.getVnfPackageId(), request.getAdditionalParam());
214         validateVimType(additionalParameters.getVimType());
215         VnfCreationResult creationResult = create(vnfmId, request.getVnfDescriptorId(), request.getVnfInstanceName(), request.getVnfInstanceDescription());
216         return instantiate(vnfmId, request.getExtVirtualLink(), httpResponse, request.getAdditionalParam(), additionalParameters, creationResult.vnfInfo.getId(), request.getVnfPackageId(), creationResult.vnfdId);
217     }
218
219     @SuppressWarnings("squid:S00107") //wrapping them into an object makes the code less readable
220     private void instantiateVnf(String vnfmId, List<ExtVirtualLinkInfo> extVirtualLinkInfos, AdditionalParameters additionalParameters, String onapVnfdId, String vnfmVnfdId, String vnfId, String vimId, JobInfo jobInfo) {
221         String vnfdContent = catalogManager.getCbamVnfdContent(vnfmId, vnfmVnfdId);
222         addSpecifiedExtensions(vnfmId, vnfId, additionalParameters);
223         GrantVNFResponseVim vim = grantManager.requestGrantForInstantiate(vnfmId, vnfId, vimId, onapVnfdId, additionalParameters.getInstantiationLevel(), vnfdContent, jobInfo.getJobId());
224         handleBackwardIncompatibleApiChangesInVfc(vim);
225         VimInfo vimInfo = vimInfoProvider.getVimInfo(vim.getVimId());
226         InstantiateVnfRequest instantiationRequest = new InstantiateVnfRequest();
227         addExternalLinksToRequest(extVirtualLinkInfos, additionalParameters, instantiationRequest, vimId);
228         instantiationRequest.getVims().add(addVim(additionalParameters, vimId, vim, vimInfo));
229         instantiationRequest.setFlavourId(getFlavorId(vnfdContent));
230         instantiationRequest.setComputeResourceFlavours(additionalParameters.getComputeResourceFlavours());
231         instantiationRequest.setGrantlessMode(true);
232         instantiationRequest.setInstantiationLevelId(additionalParameters.getInstantiationLevel());
233         instantiationRequest.setSoftwareImages(additionalParameters.getSoftwareImages());
234         instantiationRequest.setZones(additionalParameters.getZones());
235         instantiationRequest.setExtManagedVirtualLinks(additionalParameters.getExtManagedVirtualLinks());
236         for (ExtVirtualLinkData extVirtualLinkData : additionalParameters.getExtVirtualLinks()) {
237             instantiationRequest.addExtVirtualLinksItem(extVirtualLinkData);
238         }
239         JsonObject root = new Gson().toJsonTree(jobInfo).getAsJsonObject();
240         if (additionalParameters.getAdditionalParams() != null) {
241             for (Map.Entry<String, JsonElement> item : new Gson().toJsonTree(additionalParameters.getAdditionalParams()).getAsJsonObject().entrySet()) {
242                 root.add(item.getKey(), item.getValue());
243             }
244         } else {
245             logger.warn("No additional parameters were specified for the operation");
246         }
247         instantiationRequest.setAdditionalParams(root);
248         OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdInstantiatePost(vnfId, instantiationRequest, NOKIA_LCM_API_VERSION).blockingFirst();
249         waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
250     }
251
252     private void handleBackwardIncompatibleApiChangesInVfc(GrantVNFResponseVim vim) {
253         if (vim.getVimId() == null) {
254             if (vim.getVimid() == null) {
255                 throw buildFatalFailure(logger, "VF-C did not send VIM identifier in grant response");
256             } else {
257                 vim.setVimId(vim.getVimid());
258             }
259         }
260         if (vim.getAccessInfo() == null) {
261             if (vim.getAccessinfo() == null) {
262                 throw buildFatalFailure(logger, "VF-C did not send access info in grant response");
263             } else {
264                 vim.setAccessInfo(vim.getAccessinfo());
265             }
266         }
267     }
268
269     private com.nokia.cbam.lcm.v32.model.VimInfo addVim(AdditionalParameters additionalParameters, String vimId, GrantVNFResponseVim vim, VimInfo vimInfo) {
270         if (additionalParameters.getVimType() == OPENSTACK_V2_INFO) {
271             return buildOpenStackV2INFO(vimId, vim, vimInfo);
272
273         } else if (additionalParameters.getVimType() == OPENSTACK_V3_INFO) {
274             if (isEmpty(vimInfo.getDomain())) {
275                 if (isEmpty(additionalParameters.getDomain())) {
276                     throw buildFatalFailure(logger, "The cloud did not supply the cloud domain (Amsterdam release) and was not supplied as additional data");
277                 } else {
278                     logger.warn("Setting domain from additional parameters");
279                     vimInfo.setDomain(additionalParameters.getDomain());
280                 }
281             }
282             return buildOpenStackV3INFO(vimId, vim, vimInfo);
283         } else {
284             //OTHER VIM TYPE is not possible
285             return buildVcloudInfo(vimId, vimInfo);
286         }
287     }
288
289     private void validateVimType(com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum vimType) {
290         if (com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum.OTHER_VIM_INFO.equals(vimType)) {
291             throw buildFatalFailure(logger, "Only " + OPENSTACK_V2_INFO + ", " + OPENSTACK_V3_INFO + " and " + VMWARE_VCLOUD_INFO + " is the supported VIM types");
292         }
293     }
294
295     private String getVimId(Object additionalParams) {
296         return childElement(new Gson().toJsonTree(additionalParams).getAsJsonObject(), "vimId").getAsString();
297     }
298
299     private AdditionalParameters convertInstantiationAdditionalParams(String csarId, Object additionalParams) {
300         JsonObject root = new Gson().toJsonTree(additionalParams).getAsJsonObject();
301         if(root.has(PROPERTIES)){
302             JsonObject properties = new JsonParser().parse(root.get(PROPERTIES).getAsString()).getAsJsonObject();
303             if(properties.has(ETSI_CONFIG)){
304                 JsonElement etsiConfig = properties.get(ETSI_CONFIG);
305                 return new Gson().fromJson(etsiConfig.getAsString(), AdditionalParameters.class);
306             }
307             else{
308                 logger.info("The instantiation input for VNF with {} CSAR id does not have an " + ETSI_CONFIG +" section", csarId);
309             }
310         }
311         else{
312             logger.info("The instantiation input for VNF with {} CSAR id does not have a properties section", csarId);
313         }
314         JsonObject inputs = child(root, "inputs");
315         if (!inputs.has(csarId)) {
316             throw buildFatalFailure(logger, "The additional parameter section does not contain settings for VNF with " + csarId + " CSAR id");
317         }
318         JsonElement additionalParamsForVnf = new JsonParser().parse(inputs.get(csarId).getAsString());
319         return new Gson().fromJson(additionalParamsForVnf, AdditionalParameters.class);
320     }
321
322     private String getFlavorId(String vnfdContent) {
323         JsonObject root = new Gson().toJsonTree(new Yaml().load(vnfdContent)).getAsJsonObject();
324         JsonObject capabilities = child(child(child(root, "topology_template"), "substitution_mappings"), "capabilities");
325         JsonObject deploymentFlavorProperties = child(child(capabilities, "deployment_flavour"), PROPERTIES);
326         return childElement(deploymentFlavorProperties, "flavour_id").getAsString();
327     }
328
329     private Set<Map.Entry<String, JsonElement>> getAcceptableOperationParameters(String vnfdContent, String categoryOfOperation, String operationName) {
330         JsonObject root = new Gson().toJsonTree(new Yaml().load(vnfdContent)).getAsJsonObject();
331         JsonObject interfaces = child(child(child(root, "topology_template"), "substitution_mappings"), "interfaces");
332         JsonObject additionalParameters = child(child(child(child(interfaces, categoryOfOperation), operationName), "inputs"), "additional_parameters");
333         return additionalParameters.entrySet();
334     }
335
336     private void addExternalLinksToRequest(List<ExtVirtualLinkInfo> extVirtualLinks, AdditionalParameters additionalParameters, InstantiateVnfRequest instantiationRequest, String vimId) {
337         for (ExtVirtualLinkInfo extVirtualLink : extVirtualLinks) {
338             ExtVirtualLinkData cbamExternalVirtualLink = new ExtVirtualLinkData();
339             cbamExternalVirtualLink.setVimId(vimId);
340             cbamExternalVirtualLink.setResourceId(extVirtualLink.getResourceId());
341             VnfExtCpData ecp = new VnfExtCpData();
342             cbamExternalVirtualLink.setExtVirtualLinkId(extVirtualLink.getVlInstanceId());
343             cbamExternalVirtualLink.getExtCps().add(ecp);
344             ecp.setCpdId(extVirtualLink.getCpdId());
345             List<NetworkAddress> addresses = additionalParameters.getExternalConnectionPointAddresses().get(extVirtualLink.getCpdId());
346             ecp.setAddresses(addresses);
347             instantiationRequest.addExtVirtualLinksItem(cbamExternalVirtualLink);
348         }
349     }
350
351     private void addVnfdIdToVnfModifyableAttributeExtensions(String vnfmId, String vnfId, String onapCsarId) {
352         ModifyVnfInfoRequest request = new ModifyVnfInfoRequest();
353         request.setExtensions(new ArrayList<>());
354         VnfProperty onapCsarIdProperty = new VnfProperty();
355         onapCsarIdProperty.setName(ONAP_CSAR_ID);
356         onapCsarIdProperty.setValue(onapCsarId);
357         request.getExtensions().add(onapCsarIdProperty);
358         VnfProperty externalVnfmIdProperty = new VnfProperty();
359         externalVnfmIdProperty.setName(EXTERNAL_VNFM_ID);
360         externalVnfmIdProperty.setValue(vnfmId);
361         request.getExtensions().add(externalVnfmIdProperty);
362         executeModifyVnfInfo(vnfmId, vnfId, request);
363     }
364
365     private void executeModifyVnfInfo(String vnfmId, String vnfId, ModifyVnfInfoRequest request) {
366         try {
367             OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdPatch(vnfId, request, NOKIA_LCM_API_VERSION).blockingFirst();
368             waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
369         } catch (Exception e) {
370             String properties = Joiner.on(",").join(natural().sortedCopy(transform(request.getExtensions(), VnfProperty::getName)));
371             throw buildFatalFailure(logger, "Unable to set the " + properties + " properties on the VNF with " + vnfId + " identifier", e);
372         }
373     }
374
375     private void addSpecifiedExtensions(String vnfmId, String vnfId, AdditionalParameters additionalParameters){
376         if(!additionalParameters.getExtensions().isEmpty()){
377             ModifyVnfInfoRequest request = new ModifyVnfInfoRequest();
378             request.setExtensions(new ArrayList<>());
379             request.getExtensions().addAll(additionalParameters.getExtensions());
380             executeModifyVnfInfo(vnfmId, vnfId, request);
381         }
382         else{
383             logger.info("No extensions specified for VNF with {} identifier", vnfId);
384         }
385     }
386
387     private OPENSTACKV3INFO buildOpenStackV3INFO(String vimId, GrantVNFResponseVim vim, org.onap.vnfmdriver.model.VimInfo vimInfo) {
388         OPENSTACKV3INFO openstackv3INFO = new OPENSTACKV3INFO();
389         openstackv3INFO.setVimInfoType(OPENSTACK_V3_INFO);
390         OpenStackAccessInfoV3 accessInfov3 = new OpenStackAccessInfoV3();
391         openstackv3INFO.accessInfo(accessInfov3);
392         accessInfov3.setPassword(vimInfo.getPassword());
393         accessInfov3.setDomain(vimInfo.getDomain());
394         accessInfov3.setProject(vim.getAccessInfo().getTenant());
395         accessInfov3.setRegion(getRegionName(vimId));
396         accessInfov3.setUsername(vimInfo.getUserName());
397         openstackv3INFO.setInterfaceInfo(getEndpointInfo(vimInfo));
398         openstackv3INFO.setId(vimId);
399         return openstackv3INFO;
400     }
401
402     private OPENSTACKV2INFO buildOpenStackV2INFO(String vimId, GrantVNFResponseVim vim, org.onap.vnfmdriver.model.VimInfo vimInfo) {
403         OPENSTACKV2INFO openstackv2INFO = new OPENSTACKV2INFO();
404         openstackv2INFO.setVimInfoType(OPENSTACK_V2_INFO);
405         OpenStackAccessInfoV2 accessInfo = new OpenStackAccessInfoV2();
406         openstackv2INFO.setAccessInfo(accessInfo);
407         accessInfo.setPassword(vimInfo.getPassword());
408         accessInfo.setTenant(vim.getAccessInfo().getTenant());
409         accessInfo.setUsername(vimInfo.getUserName());
410         accessInfo.setRegion(getRegionName(vimId));
411         EndpointInfo interfaceEndpoint = getEndpointInfo(vimInfo);
412         openstackv2INFO.setInterfaceInfo(interfaceEndpoint);
413         openstackv2INFO.setId(vimId);
414         return openstackv2INFO;
415     }
416
417     private EndpointInfo getEndpointInfo(VimInfo vimInfo) {
418         EndpointInfo interfaceEndpoint = new EndpointInfo();
419         if (!isEmpty(vimInfo.getSslInsecure())) {
420             interfaceEndpoint.setSkipCertificateHostnameCheck(Boolean.parseBoolean(vimInfo.getSslInsecure()));
421             interfaceEndpoint.setSkipCertificateVerification(Boolean.parseBoolean(vimInfo.getSslInsecure()));
422         } else {
423             interfaceEndpoint.setSkipCertificateHostnameCheck(true);
424             interfaceEndpoint.setSkipCertificateVerification(true);
425         }
426         interfaceEndpoint.setEndpoint(vimInfo.getUrl());
427         if (!interfaceEndpoint.isSkipCertificateVerification()) {
428             interfaceEndpoint.setTrustedCertificates(new ArrayList<>());
429             for (String trustedCertificate : StoreLoader.getCertifacates(vimInfo.getSslCacert())) {
430                 interfaceEndpoint.getTrustedCertificates().add(trustedCertificate.getBytes(UTF_8));
431             }
432         }
433         return interfaceEndpoint;
434     }
435
436     private VMWAREVCLOUDINFO buildVcloudInfo(String vimId, org.onap.vnfmdriver.model.VimInfo vimInfo) {
437         VMWAREVCLOUDINFO vcloudInfo = new VMWAREVCLOUDINFO();
438         vcloudInfo.setVimInfoType(VMWARE_VCLOUD_INFO);
439         VCloudAccessInfo accessInfo = new VCloudAccessInfo();
440         vcloudInfo.setAccessInfo(accessInfo);
441         accessInfo.setPassword(vimInfo.getPassword());
442         accessInfo.setUsername(vimInfo.getUserName());
443         accessInfo.setOrganization(getRegionName(vimId));
444         vcloudInfo.setInterfaceInfo(getEndpointInfo(vimInfo));
445         vcloudInfo.setId(vimId);
446         return vcloudInfo;
447     }
448
449     /**
450      * Terminates and deletes the VNF
451      * <ul>
452      * <li>fails if the VNF does not exist</li>
453      * <li>terminates if instantiated</li>
454      * <li>deletes the VNF</li>
455      * </ul>
456      *
457      * @param vnfmId       the identifier of the VNFM
458      * @param vnfId        the identifier of the VNF
459      * @param request      the termination request
460      * @param httpResponse the HTTP response
461      * @return the job for polling the progress of the termination
462      */
463     public JobInfo terminateAndDelete(String vnfmId, String vnfId, VnfTerminateRequest request, HttpServletResponse httpResponse) {
464         logOperationInput(vnfId, "termination", request);
465         return scheduleExecution(vnfId, httpResponse, "terminateVnf", jobInfo -> {
466             terminateVnf(vnfmId, vnfId, request, jobInfo);
467             deleteVnf(vnfmId, vnfId);
468         });
469     }
470
471     /**
472      * Terminates the VNF
473      * <ul>
474      * <li>fails if the VNF does not exist</li>
475      * <li>terminates if instantiated</li>
476      * <li>deletes the VNF</li>
477      * </ul>
478      *
479      * @param vnfmId       the identifier of the VNFM
480      * @param vnfId        the identifier of the VNF
481      * @param request      the termination request
482      * @param httpResponse the HTTP response
483      * @return the job for polling the progress of the termination
484      */
485     public JobInfo terminate(String vnfmId, String vnfId, VnfTerminateRequest request, HttpServletResponse httpResponse) {
486         logOperationInput(vnfId, "termination", request);
487         return scheduleExecution(vnfId, httpResponse, "terminate", jobInfo -> terminateVnf(vnfmId, vnfId, request, jobInfo));
488     }
489
490     private void terminateVnf(String vnfmId, String vnfId, VnfTerminateRequest request, JobInfo jobInfo) {
491         TerminateVnfRequest cbamRequest = new TerminateVnfRequest();
492         setState(request, cbamRequest);
493         cbamRequest.setAdditionalParams(new Gson().toJsonTree(jobInfo).getAsJsonObject());
494         com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
495         if (vnf.getInstantiationState() == INSTANTIATED) {
496             String vimId = getVimIdFromInstantiationRequest(vnfmId, vnf);
497             grantManager.requestGrantForTerminate(vnfmId, vnfId, vimId, getVnfdIdFromModifyableAttributes(vnf), vnf, jobInfo.getJobId());
498             OperationExecution terminationOperation = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdTerminatePost(vnfId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
499             OperationExecution finishedOperation = waitForOperationToFinish(vnfmId, vnfId, terminationOperation.getId());
500             if (finishedOperation.getStatus() == FINISHED) {
501                 notificationManager.waitForTerminationToBeProcessed(finishedOperation.getId());
502             } else {
503                 throw buildFatalFailure(logger, "Unable to terminate VNF the operation did not finish with success");
504             }
505         } else {
506             logger.warn("The VNF with {} identifier is not instantiated no termination is required", vnfId);
507         }
508     }
509
510     private void setState(VnfTerminateRequest request, TerminateVnfRequest cbamRequest) {
511         if (request.getTerminationType() == null) {
512             cbamRequest.setTerminationType(TerminationType.FORCEFUL);
513         } else {
514             if (request.getTerminationType().equals(VnfTerminationType.GRACEFUL)) {
515                 cbamRequest.setTerminationType(TerminationType.GRACEFUL);
516                 cbamRequest.setGracefulTerminationTimeout(parseInt(request.getGracefulTerminationTimeout()));
517             } else {
518                 cbamRequest.setTerminationType(TerminationType.FORCEFUL);
519             }
520         }
521     }
522
523     /**
524      * Delete the VNF
525      *
526      * @param vnfmId the identifier of the VNFM
527      * @param vnfId  the identifier fo the VNF
528      */
529     public void deleteVnf(String vnfmId, String vnfId) {
530         logger.info("Deleting VNF with {} identifier", vnfId);
531         cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdDelete(vnfId, NOKIA_LCM_API_VERSION).blockingFirst(null);
532         logger.info("The VNF with {} identifier has been deleted", vnfId);
533     }
534
535     private String getVimIdFromInstantiationRequest(String vnfmId, com.nokia.cbam.lcm.v32.model.VnfInfo vnf) {
536         OperationExecution lastInstantiation = findLastInstantiation(vnf.getOperationExecutions());
537         Object operationParameters = cbamRestApiProvider.getCbamOperationExecutionApi(vnfmId).operationExecutionsOperationExecutionIdOperationParamsGet(lastInstantiation.getId(), NOKIA_LCM_API_VERSION).blockingFirst();
538         JsonObject root = new Gson().toJsonTree(operationParameters).getAsJsonObject();
539         return childElement(childElement(root, "vims").getAsJsonArray().get(0).getAsJsonObject(), "id").getAsString();
540     }
541
542     /**
543      * @param vnfmId the identifier of the VNFM
544      * @param vnfId  the identifier of the VNF
545      * @return the current state of the VNF
546      */
547     public VnfInfo queryVnf(String vnfmId, String vnfId) {
548         try {
549             com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
550             return convertVnfInfo(vnfId, cbamVnfInfo);
551         } catch (Exception e) {
552             throw buildFatalFailure(logger, "Unable to query VNF (" + vnfId + ")", e);
553         }
554     }
555
556     private VnfInfo convertVnfInfo(String vnfId, com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo) {
557         VnfInfo vnfInfo = new VnfInfo();
558         vnfInfo.setVersion(cbamVnfInfo.getVnfSoftwareVersion());
559         vnfInfo.setVnfInstanceId(vnfId);
560         String onapCsarId = getVnfdIdFromModifyableAttributes(cbamVnfInfo);
561         vnfInfo.setVnfdId(onapCsarId);
562         vnfInfo.setVnfPackageId(onapCsarId);
563         vnfInfo.setVnfInstanceDescription(cbamVnfInfo.getDescription());
564         vnfInfo.setVnfInstanceName(cbamVnfInfo.getName());
565         vnfInfo.setVnfProvider(cbamVnfInfo.getVnfProvider());
566         vnfInfo.setVnfStatus("ACTIVE");
567         vnfInfo.setVnfType("Kuku");
568         return vnfInfo;
569     }
570
571     private ScaleDirection convert(org.onap.vnfmdriver.model.ScaleDirection direction) {
572         if (org.onap.vnfmdriver.model.ScaleDirection.IN.equals(direction)) {
573             return ScaleDirection.IN;
574         } else {
575             return ScaleDirection.OUT;
576         }
577     }
578
579     /**
580      * Scale the VNF
581      *
582      * @param vnfmId       the identifier of the VNFM
583      * @param vnfId        the identifier of the VNF
584      * @param request      the scale request
585      * @param httpResponse the HTTP response
586      * @return the job for tracking the scale
587      */
588     public JobInfo scaleVnf(String vnfmId, String vnfId, VnfScaleRequest request, HttpServletResponse httpResponse) {
589         logOperationInput(vnfId, SCALE_OPERATION_NAME, request);
590         return scheduleExecution(vnfId, httpResponse, SCALE_OPERATION_NAME, jobInfo -> {
591             ScaleVnfRequest cbamRequest = new ScaleVnfRequest();
592             cbamRequest.setAspectId(request.getAspectId());
593             cbamRequest.setNumberOfSteps(Integer.valueOf(request.getNumberOfSteps()));
594             cbamRequest.setType(convert(request.getType()));
595             com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
596             JsonObject root = new Gson().toJsonTree(jobInfo).getAsJsonObject();
597             com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
598             String vnfdContent = catalogManager.getCbamVnfdContent(vnfmId, cbamVnfInfo.getVnfdId());
599             Set<Map.Entry<String, JsonElement>> acceptableOperationParameters = getAcceptableOperationParameters(vnfdContent, "Basic", SCALE_OPERATION_NAME);
600             buildAdditionalParameters(request, root, acceptableOperationParameters);
601             cbamRequest.setAdditionalParams(root);
602             grantManager.requestGrantForScale(vnfmId, vnfId, getVimIdFromInstantiationRequest(vnfmId, vnf), getVnfdIdFromModifyableAttributes(vnf), request, jobInfo.getJobId());
603             OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdScalePost(vnfId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
604             waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
605         });
606     }
607
608     private void buildAdditionalParameters(VnfScaleRequest request, JsonObject root, Set<Map.Entry<String, JsonElement>> acceptableOperationParameters) {
609         if (request.getAdditionalParam() != null) {
610             for (Map.Entry<String, JsonElement> item : new Gson().toJsonTree(request.getAdditionalParam()).getAsJsonObject().entrySet()) {
611                 if (isParameterAccepted(acceptableOperationParameters, item)) {
612                     root.add(item.getKey(), item.getValue());
613                 }
614             }
615         } else {
616             logger.warn("No additional parameters were passed for scaling");
617         }
618     }
619
620     private boolean isParameterAccepted(Set<Map.Entry<String, JsonElement>> acceptableOperationParameters, Map.Entry<String, JsonElement> item) {
621         boolean found = false;
622         for (Map.Entry<String, JsonElement> acceptableOperationParameter : acceptableOperationParameters) {
623             if (acceptableOperationParameter.getKey().equals(item.getKey())) {
624                 found = true;
625             }
626         }
627         return found;
628     }
629
630     /**
631      * Heal the VNF
632      *
633      * @param vnfmId       the identifier of the VNFM
634      * @param vnfId        the identifier of the VNF
635      * @param request      the heal request
636      * @param httpResponse the HTTP response
637      * @param vnfcId       the identifer of thr VNFC to be healed
638      * @return the job for tracking the heal
639      */
640     public JobInfo healVnf(String vnfmId, String vnfId, VnfHealRequest request, Optional<String> vnfcId, HttpServletResponse httpResponse) {
641         logOperationInput(vnfId, "heal", request);
642         return scheduleExecution(vnfId, httpResponse, "heal", job -> {
643             HealVnfRequest cbamHealRequest = new HealVnfRequest();
644             Map<String, String> additionalParams = new HashMap<>();
645             additionalParams.put("vmName", request.getAffectedvm().getVmname());
646             additionalParams.put("action", request.getAction());
647             additionalParams.put("jobId", job.getJobId());
648             additionalParams.put("vnfcId", vnfcId.orElse("unknown"));
649             cbamHealRequest.setAdditionalParams(additionalParams);
650             com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
651             String vimId = getVimIdFromInstantiationRequest(vnfmId, vnf);
652             grantManager.requestGrantForHeal(vnfmId, vnfId, vimId, getVnfdIdFromModifyableAttributes(vnf), request, job.getJobId());
653             OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdHealPost(vnfId, cbamHealRequest, NOKIA_LCM_API_VERSION).blockingFirst();
654             waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
655         });
656     }
657
658     public JobInfo customOperation(String vnfmId, String vnfId, String operationId, Object additionalParams, HttpServletResponse httpResponse) {
659         logOperationInput(vnfId, "custom", additionalParams);
660         return scheduleExecution(vnfId, httpResponse, "custom", job -> {
661             CustomOperationRequest cbamRequest = new CustomOperationRequest();
662             cbamRequest.setAdditionalParams(additionalParams);
663             OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdCustomCustomOperationNamePost(vnfId, operationId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
664             waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
665         });
666     }
667
668     private JobInfo scheduleExecution(String vnfId, HttpServletResponse httpResponse, String operation, AsynchronousExecution asynchronExecution) {
669         JobInfo jobInfo = new JobInfo();
670         jobInfo.setJobId(jobManager.spawnJob(vnfId, httpResponse));
671         executorService.submit(() -> {
672             try {
673                 asynchronExecution.execute(jobInfo);
674             } catch (RuntimeException e) {
675                 logger.error("Unable to " + operation + " VNF with " + vnfId + " identifier", e);
676                 jobManager.jobFinished(jobInfo.getJobId());
677                 throw e;
678             }
679             jobManager.jobFinished(jobInfo.getJobId());
680         });
681         return jobInfo;
682     }
683
684     private OperationExecution waitForOperationToFinish(String vnfmId, String vnfId, String operationExecutionId) {
685         while (true) {
686             try {
687                 OperationExecution operationExecution = find(cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdOperationExecutionsGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst(), opEx -> operationExecutionId.equals(opEx.getId()));
688                 if (hasOperationFinished(operationExecution)) {
689                     logger.debug("Operation finished with " + operationExecution.getId());
690                     return operationExecution;
691                 }
692             } catch (Exception e) {
693                 //swallow exception and retry
694                 logger.warn("Unable to retrieve operations details", e);
695             }
696             systemFunctions().sleep(OPERATION_STATUS_POLLING_INTERVAL_IN_MS);
697         }
698     }
699
700     private boolean hasOperationFinished(OperationExecution operationExecution) {
701         return newHashSet(FINISHED, OperationStatus.FAILED).contains(operationExecution.getStatus());
702     }
703
704     @FunctionalInterface
705     private interface AsynchronousExecution {
706         void execute(JobInfo job);
707     }
708
709     public static class VnfCreationResult {
710         private final com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo;
711
712         private final String vnfdId;
713
714         public VnfCreationResult(com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo, String vnfdId) {
715             this.vnfInfo = vnfInfo;
716             this.vnfdId = vnfdId;
717         }
718
719         public com.nokia.cbam.lcm.v32.model.VnfInfo getVnfInfo() {
720             return vnfInfo;
721         }
722     }
723 }