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