2 * Copyright 2016-2017, Nokia Corporation
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm;
20 import com.google.gson.Gson;
21 import com.google.gson.JsonElement;
22 import com.google.gson.JsonObject;
23 import com.google.gson.JsonParser;
24 import com.nokia.cbam.catalog.v1.model.CatalogAdapterVnfpackage;
25 import com.nokia.cbam.lcm.v32.model.*;
26 import com.nokia.cbam.lcm.v32.model.ScaleDirection;
28 import java.util.concurrent.ExecutorService;
29 import java.util.concurrent.Executors;
30 import javax.servlet.http.HttpServletResponse;
31 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.api.IGrantManager;
32 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.api.VimInfoProvider;
33 import org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.StoreLoader;
34 import org.onap.vnfmdriver.model.ExtVirtualLinkInfo;
35 import org.onap.vnfmdriver.model.*;
36 import org.onap.vnfmdriver.model.VimInfo;
37 import org.onap.vnfmdriver.model.VnfInfo;
38 import org.slf4j.Logger;
39 import org.yaml.snakeyaml.Yaml;
41 import static java.lang.Integer.parseInt;
42 import static java.nio.charset.StandardCharsets.UTF_8;
44 import static com.google.common.base.Splitter.on;
45 import static com.google.common.collect.Iterables.find;
46 import static com.google.common.collect.Lists.newArrayList;
47 import static com.google.common.collect.Sets.newHashSet;
48 import static com.nokia.cbam.lcm.v32.model.InstantiationState.INSTANTIATED;
49 import static com.nokia.cbam.lcm.v32.model.OperationStatus.FINISHED;
50 import static com.nokia.cbam.lcm.v32.model.OperationType.INSTANTIATE;
51 import static com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum.*;
52 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.CbamUtils.*;
53 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.SystemFunctions.systemFunctions;
54 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.CbamRestApiProvider.NOKIA_LCM_API_VERSION;
55 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.notification.LifecycleChangeNotificationManager.NEWEST_OPERATIONS_FIRST;
56 import static org.slf4j.LoggerFactory.getLogger;
57 import static org.springframework.util.StringUtils.isEmpty;
60 * Responsible for executing lifecycle operation on the VNF
62 public class LifecycleManager {
63 public static final String ONAP_CSAR_ID = "onapCsarId";
64 public static final long OPERATION_STATUS_POLLING_INTERVAL_IN_MS = 5000L;
66 * The key of the CBAM VNF extension for the identifier of the VNFM in ONAP
68 public static final String EXTERNAL_VNFM_ID = "externalVnfmId";
69 public static final String SCALE_OPERATION_NAME = "scale";
70 public static final String ETSI_CONFIG = "etsi_config";
71 private static Logger logger = getLogger(LifecycleManager.class);
72 private final CatalogManager catalogManager;
73 private final IGrantManager grantManager;
74 private final JobManager jobManager;
75 private final ILifecycleChangeNotificationManager notificationManager;
76 private final CbamRestApiProvider cbamRestApiProvider;
77 private final VimInfoProvider vimInfoProvider;
80 * Runs asynchronous operations in the background
82 private ExecutorService executorService = Executors.newCachedThreadPool();
84 LifecycleManager(CatalogManager catalogManager, IGrantManager grantManager, CbamRestApiProvider restApiProvider, VimInfoProvider vimInfoProvider, JobManager jobManager, ILifecycleChangeNotificationManager notificationManager) {
85 this.vimInfoProvider = vimInfoProvider;
86 this.grantManager = grantManager;
87 this.cbamRestApiProvider = restApiProvider;
88 this.jobManager = jobManager;
89 this.notificationManager = notificationManager;
90 this.catalogManager = catalogManager;
94 * @param vimId the VIM identifier
95 * @return the name of the region
97 public static String getRegionName(String vimId) {
98 return newArrayList(on(SEPARATOR).split(vimId)).get(1);
102 * @param vimId the VIM identifier
103 * @return the owner of the cloud
105 public static String getCloudOwner(String vimId) {
106 return newArrayList(on(SEPARATOR).split(vimId)).get(0);
109 private static OperationExecution findLastInstantiation(List<OperationExecution> operationExecutions) {
110 return find(NEWEST_OPERATIONS_FIRST.sortedCopy(operationExecutions), op -> INSTANTIATE.equals(op.getOperationType()));
113 public static String getVnfdIdFromModifyableAttributes(com.nokia.cbam.lcm.v32.model.VnfInfo vnf) {
114 return find(vnf.getExtensions(), p -> p.getName().equals(ONAP_CSAR_ID)).getValue().toString();
118 * Create the VNF. It consists of the following steps
120 * <li>upload the VNF package to CBAM package (if not already there)</li>
121 * <li>create the VNF on CBAM</li>
122 * <li>modify attributes of the VNF (add onapCsarId field)</li>
124 * The rollback of the failed operation is not implemented
126 * <li>delete the VNF if error occurs before instantiation</li>
127 * <li>terminateVnf & delete VNF if error occurs after instantiation</li>
130 * @param vnfmId the identifier of the VNFM
131 * @param csarId the identifier of the VNF package
132 * @param vnfName the name of the VNF
133 * @param description the description of the VNF
134 * @return the VNF creation result
136 public VnfCreationResult create(String vnfmId, String csarId, String vnfName, String description) {
137 logOperationInput("not yet specified", "creation", csarId);
139 CatalogAdapterVnfpackage cbamPackage = catalogManager.preparePackageInCbam(vnfmId, csarId);
140 CreateVnfRequest vnfCreateRequest = new CreateVnfRequest();
141 vnfCreateRequest.setVnfdId(cbamPackage.getVnfdId());
142 vnfCreateRequest.setName(vnfName);
143 vnfCreateRequest.setDescription(description);
144 com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsPost(vnfCreateRequest, NOKIA_LCM_API_VERSION).blockingFirst();
145 addVnfdIdToVnfModifyableAttributeExtensions(vnfmId, vnfInfo.getId(), csarId);
146 return new VnfCreationResult(vnfInfo, cbamPackage.getVnfdId());
147 } catch (Exception e) {
148 throw buildFatalFailure(logger, "Unable to create the VNF", e);
152 private void logOperationInput(String vnfId, String operationName, Object payload) {
153 if (logger.isInfoEnabled()) {
154 logger.info("Starting {} operation on VNF with {} identifier with {} parameter", operationName, vnfId, new Gson().toJson(payload));
159 * Instantiate the VNF
161 * @param vnfmId the identifier of the VNFM
162 * @param externalVirtualLinks the external virtual links of the VNF
163 * @param httpResponse the HTTP response that corresponds to the VNF instantiation request
164 * @param additionalParameters additional parameters
165 * @param vnfId the identifier of the VNF
166 * @param vnfmVnfdId the identifier of the VNF package in CBAM
167 * @param operationAdditionalParameters the additional parameters of the operation
168 * @param onapVnfdId the identifier of the VNFD in the VNFM
169 * @return the instantiation response
171 @SuppressWarnings("squid:S00107") //wrapping them into an object makes the code less readable
172 public VnfInstantiateResponse instantiate(String vnfmId, List<ExtVirtualLinkInfo> externalVirtualLinks, HttpServletResponse httpResponse, Object operationAdditionalParameters, AdditionalParameters additionalParameters, String vnfId, String onapVnfdId, String vnfmVnfdId) {
173 logOperationInput(vnfId, "instantiation", additionalParameters);
174 validateVimType(additionalParameters.getVimType());
175 VnfInstantiateResponse response = new VnfInstantiateResponse();
176 response.setVnfInstanceId(vnfId);
177 String vimId = getVimId(operationAdditionalParameters);
178 JobInfo spawnJob = scheduleExecution(vnfId, httpResponse, "instantiate", jobInfo ->
179 instantiateVnf(vnfmId, externalVirtualLinks, additionalParameters, onapVnfdId, vnfmVnfdId, vnfId, vimId, jobInfo)
181 response.setJobId(spawnJob.getJobId());
186 * Instantiate (VF-C terminology) the VNF. It consists of the following steps
188 * <li>upload the VNF package to CBAM package (if not already there)</li>
189 * <li>create the VNF on CBAM</li>
190 * <li>modify attributes of the VNF (add onapCsarId field)</li>
191 * <li>asynchronously</li>
192 * <li>request grant from VF-C</li>
193 * <li>instantiate VNF on CBAM</li>
194 * <li>return VNF & job id (after create VNF on CBAM)</li>
197 * The rollback of the failed operation is not implemented
199 * <li>delete the VNF if error occurs before instantiation</li>
200 * <li>terminateVnf & delete VNf if error occurs after instantiation</li>
203 * @param vnfmId the identifier of the VNFM
204 * @param request the instantiation request
205 * @param httpResponse the HTTP response
206 * @return the instantiation response
208 public VnfInstantiateResponse createAndInstantiate(String vnfmId, VnfInstantiateRequest request, HttpServletResponse httpResponse) {
209 AdditionalParameters additionalParameters = convertInstantiationAdditionalParams(request.getVnfPackageId(), request.getAdditionalParam());
210 validateVimType(additionalParameters.getVimType());
211 VnfCreationResult creationResult = create(vnfmId, request.getVnfDescriptorId(), request.getVnfInstanceName(), request.getVnfInstanceDescription());
212 return instantiate(vnfmId, request.getExtVirtualLink(), httpResponse, request.getAdditionalParam(), additionalParameters, creationResult.vnfInfo.getId(), request.getVnfPackageId(), creationResult.vnfdId);
215 @SuppressWarnings("squid:S00107") //wrapping them into an object makes the code less readable
216 private void instantiateVnf(String vnfmId, List<ExtVirtualLinkInfo> extVirtualLinkInfos, AdditionalParameters additionalParameters, String onapVnfdId, String vnfmVnfdId, String vnfId, String vimId, JobInfo jobInfo) {
217 String vnfdContent = catalogManager.getCbamVnfdContent(vnfmId, vnfmVnfdId);
218 GrantVNFResponseVim vim = grantManager.requestGrantForInstantiate(vnfmId, vnfId, vimId, onapVnfdId, additionalParameters.getInstantiationLevel(), vnfdContent, jobInfo.getJobId());
219 handleBackwardIncompatibleApiChangesInVfc(vim);
220 VimInfo vimInfo = vimInfoProvider.getVimInfo(vim.getVimId());
221 InstantiateVnfRequest instantiationRequest = new InstantiateVnfRequest();
222 addExternalLinksToRequest(extVirtualLinkInfos, additionalParameters, instantiationRequest, vimId);
223 instantiationRequest.getVims().add(addVim(additionalParameters, vimId, vim, vimInfo));
224 instantiationRequest.setFlavourId(getFlavorId(vnfdContent));
225 instantiationRequest.setComputeResourceFlavours(additionalParameters.getComputeResourceFlavours());
226 instantiationRequest.setGrantlessMode(true);
227 instantiationRequest.setInstantiationLevelId(additionalParameters.getInstantiationLevel());
228 instantiationRequest.setSoftwareImages(additionalParameters.getSoftwareImages());
229 instantiationRequest.setZones(additionalParameters.getZones());
230 instantiationRequest.setExtManagedVirtualLinks(additionalParameters.getExtManagedVirtualLinks());
231 for (ExtVirtualLinkData extVirtualLinkData : additionalParameters.getExtVirtualLinks()) {
232 instantiationRequest.addExtVirtualLinksItem(extVirtualLinkData);
234 JsonObject root = new Gson().toJsonTree(jobInfo).getAsJsonObject();
235 if (additionalParameters.getAdditionalParams() != null) {
236 for (Map.Entry<String, JsonElement> item : new Gson().toJsonTree(additionalParameters.getAdditionalParams()).getAsJsonObject().entrySet()) {
237 root.add(item.getKey(), item.getValue());
240 logger.warn("No additional parameters were specified for the operation");
242 instantiationRequest.setAdditionalParams(root);
243 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdInstantiatePost(vnfId, instantiationRequest, NOKIA_LCM_API_VERSION).blockingFirst();
244 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
247 private void handleBackwardIncompatibleApiChangesInVfc(GrantVNFResponseVim vim) {
248 if (vim.getVimId() == null) {
249 if (vim.getVimid() == null) {
250 throw buildFatalFailure(logger, "VF-C did not send VIM identifier in grant response");
252 vim.setVimId(vim.getVimid());
255 if (vim.getAccessInfo() == null) {
256 if (vim.getAccessinfo() == null) {
257 throw buildFatalFailure(logger, "VF-C did not send access info in grant response");
259 vim.setAccessInfo(vim.getAccessinfo());
264 private com.nokia.cbam.lcm.v32.model.VimInfo addVim(AdditionalParameters additionalParameters, String vimId, GrantVNFResponseVim vim, VimInfo vimInfo) {
265 if (additionalParameters.getVimType() == OPENSTACK_V2_INFO) {
266 return buildOpenStackV2INFO(vimId, vim, vimInfo);
268 } else if (additionalParameters.getVimType() == OPENSTACK_V3_INFO) {
269 if (isEmpty(vimInfo.getDomain())) {
270 if (isEmpty(additionalParameters.getDomain())) {
271 throw buildFatalFailure(logger, "The cloud did not supply the cloud domain (Amsterdam release) and was not supplied as additional data");
273 logger.warn("Setting domain from additional parameters");
274 vimInfo.setDomain(additionalParameters.getDomain());
277 return buildOpenStackV3INFO(vimId, vim, vimInfo);
279 //OTHER VIM TYPE is not possible
280 return buildVcloudInfo(vimId, vimInfo);
284 private void validateVimType(com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum vimType) {
285 if (com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum.OTHER_VIM_INFO.equals(vimType)) {
286 throw buildFatalFailure(logger, "Only " + OPENSTACK_V2_INFO + ", " + OPENSTACK_V3_INFO + " and " + VMWARE_VCLOUD_INFO + " is the supported VIM types");
290 private String getVimId(Object additionalParams) {
291 return childElement(new Gson().toJsonTree(additionalParams).getAsJsonObject(), "vimId").getAsString();
294 private AdditionalParameters convertInstantiationAdditionalParams(String csarId, Object additionalParams) {
295 JsonObject root = new Gson().toJsonTree(additionalParams).getAsJsonObject();
296 if(root.has("properties")){
297 JsonObject properties = new JsonParser().parse(root.get("properties").getAsString()).getAsJsonObject();
298 if(properties.has(ETSI_CONFIG)){
299 JsonElement etsi_config = properties.get(ETSI_CONFIG);
300 return new Gson().fromJson(etsi_config.getAsString(), AdditionalParameters.class);
303 logger.info("The instantiation input for VNF with {} CSAR id does not have an " + ETSI_CONFIG +" section", csarId);
307 logger.info("The instantiation input for VNF with {} CSAR id does not have a properties section", csarId);
309 JsonObject inputs = child(root, "inputs");
310 if (!inputs.has(csarId)) {
311 throw buildFatalFailure(logger, "The additional parameter section does not contain settings for VNF with " + csarId + " CSAR id");
313 JsonElement additionalParamsForVnf = new JsonParser().parse(inputs.get(csarId).getAsString());
314 return new Gson().fromJson(additionalParamsForVnf, AdditionalParameters.class);
317 private String getFlavorId(String vnfdContent) {
318 JsonObject root = new Gson().toJsonTree(new Yaml().load(vnfdContent)).getAsJsonObject();
319 JsonObject capabilities = child(child(child(root, "topology_template"), "substitution_mappings"), "capabilities");
320 JsonObject deploymentFlavorProperties = child(child(capabilities, "deployment_flavour"), "properties");
321 return childElement(deploymentFlavorProperties, "flavour_id").getAsString();
324 private Set<Map.Entry<String, JsonElement>> getAcceptableOperationParameters(String vnfdContent, String categoryOfOperation, String operationName) {
325 JsonObject root = new Gson().toJsonTree(new Yaml().load(vnfdContent)).getAsJsonObject();
326 JsonObject interfaces = child(child(child(root, "topology_template"), "substitution_mappings"), "interfaces");
327 JsonObject additionalParameters = child(child(child(child(interfaces, categoryOfOperation), operationName), "inputs"), "additional_parameters");
328 return additionalParameters.entrySet();
331 private void addExternalLinksToRequest(List<ExtVirtualLinkInfo> extVirtualLinks, AdditionalParameters additionalParameters, InstantiateVnfRequest instantiationRequest, String vimId) {
332 for (ExtVirtualLinkInfo extVirtualLink : extVirtualLinks) {
333 ExtVirtualLinkData cbamExternalVirtualLink = new ExtVirtualLinkData();
334 cbamExternalVirtualLink.setVimId(vimId);
335 cbamExternalVirtualLink.setResourceId(extVirtualLink.getResourceId());
336 VnfExtCpData ecp = new VnfExtCpData();
337 cbamExternalVirtualLink.setExtVirtualLinkId(extVirtualLink.getVlInstanceId());
338 cbamExternalVirtualLink.getExtCps().add(ecp);
339 ecp.setCpdId(extVirtualLink.getCpdId());
340 List<NetworkAddress> addresses = additionalParameters.getExternalConnectionPointAddresses().get(extVirtualLink.getCpdId());
341 ecp.setAddresses(addresses);
342 instantiationRequest.addExtVirtualLinksItem(cbamExternalVirtualLink);
346 private void addVnfdIdToVnfModifyableAttributeExtensions(String vnfmId, String vnfId, String onapCsarId) {
347 ModifyVnfInfoRequest request = new ModifyVnfInfoRequest();
348 VnfProperty onapCsarIdProperty = new VnfProperty();
349 onapCsarIdProperty.setName(ONAP_CSAR_ID);
350 onapCsarIdProperty.setValue(onapCsarId);
351 request.setExtensions(new ArrayList<>());
352 request.getExtensions().add(onapCsarIdProperty);
353 VnfProperty externalVnfmIdProperty = new VnfProperty();
354 externalVnfmIdProperty.setName(EXTERNAL_VNFM_ID);
355 externalVnfmIdProperty.setValue(vnfmId);
356 request.getExtensions().add(externalVnfmIdProperty);
357 request.setVnfConfigurableProperties(null);
359 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdPatch(vnfId, request, NOKIA_LCM_API_VERSION).blockingFirst();
360 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
361 } catch (Exception e) {
362 throw buildFatalFailure(logger, "Unable to set the " + ONAP_CSAR_ID + " property on the VNF", e);
366 private OPENSTACKV3INFO buildOpenStackV3INFO(String vimId, GrantVNFResponseVim vim, org.onap.vnfmdriver.model.VimInfo vimInfo) {
367 OPENSTACKV3INFO openstackv3INFO = new OPENSTACKV3INFO();
368 openstackv3INFO.setVimInfoType(OPENSTACK_V3_INFO);
369 OpenStackAccessInfoV3 accessInfov3 = new OpenStackAccessInfoV3();
370 openstackv3INFO.accessInfo(accessInfov3);
371 accessInfov3.setPassword(vimInfo.getPassword());
372 accessInfov3.setDomain(vimInfo.getDomain());
373 accessInfov3.setProject(vim.getAccessInfo().getTenant());
374 accessInfov3.setRegion(getRegionName(vimId));
375 accessInfov3.setUsername(vimInfo.getUserName());
376 openstackv3INFO.setInterfaceInfo(getEndpointInfo(vimInfo));
377 openstackv3INFO.setId(vimId);
378 return openstackv3INFO;
381 private OPENSTACKV2INFO buildOpenStackV2INFO(String vimId, GrantVNFResponseVim vim, org.onap.vnfmdriver.model.VimInfo vimInfo) {
382 OPENSTACKV2INFO openstackv2INFO = new OPENSTACKV2INFO();
383 openstackv2INFO.setVimInfoType(OPENSTACK_V2_INFO);
384 OpenStackAccessInfoV2 accessInfo = new OpenStackAccessInfoV2();
385 openstackv2INFO.setAccessInfo(accessInfo);
386 accessInfo.setPassword(vimInfo.getPassword());
387 accessInfo.setTenant(vim.getAccessInfo().getTenant());
388 accessInfo.setUsername(vimInfo.getUserName());
389 accessInfo.setRegion(getRegionName(vimId));
390 EndpointInfo interfaceEndpoint = getEndpointInfo(vimInfo);
391 openstackv2INFO.setInterfaceInfo(interfaceEndpoint);
392 openstackv2INFO.setId(vimId);
393 return openstackv2INFO;
396 private EndpointInfo getEndpointInfo(VimInfo vimInfo) {
397 EndpointInfo interfaceEndpoint = new EndpointInfo();
398 if (!isEmpty(vimInfo.getSslInsecure())) {
399 interfaceEndpoint.setSkipCertificateHostnameCheck(Boolean.parseBoolean(vimInfo.getSslInsecure()));
400 interfaceEndpoint.setSkipCertificateVerification(Boolean.parseBoolean(vimInfo.getSslInsecure()));
402 interfaceEndpoint.setSkipCertificateHostnameCheck(true);
403 interfaceEndpoint.setSkipCertificateVerification(true);
405 interfaceEndpoint.setEndpoint(vimInfo.getUrl());
406 if (!interfaceEndpoint.isSkipCertificateVerification()) {
407 interfaceEndpoint.setTrustedCertificates(new ArrayList<>());
408 for (String trustedCertificate : StoreLoader.getCertifacates(vimInfo.getSslCacert())) {
409 interfaceEndpoint.getTrustedCertificates().add(trustedCertificate.getBytes(UTF_8));
412 return interfaceEndpoint;
415 private VMWAREVCLOUDINFO buildVcloudInfo(String vimId, org.onap.vnfmdriver.model.VimInfo vimInfo) {
416 VMWAREVCLOUDINFO vcloudInfo = new VMWAREVCLOUDINFO();
417 vcloudInfo.setVimInfoType(VMWARE_VCLOUD_INFO);
418 VCloudAccessInfo accessInfo = new VCloudAccessInfo();
419 vcloudInfo.setAccessInfo(accessInfo);
420 accessInfo.setPassword(vimInfo.getPassword());
421 accessInfo.setUsername(vimInfo.getUserName());
422 accessInfo.setOrganization(getRegionName(vimId));
423 vcloudInfo.setInterfaceInfo(getEndpointInfo(vimInfo));
424 vcloudInfo.setId(vimId);
429 * Terminates and deletes the VNF
431 * <li>fails if the VNF does not exist</li>
432 * <li>terminates if instantiated</li>
433 * <li>deletes the VNF</li>
436 * @param vnfmId the identifier of the VNFM
437 * @param vnfId the identifier of the VNF
438 * @param request the termination request
439 * @param httpResponse the HTTP response
440 * @return the job for polling the progress of the termination
442 public JobInfo terminateAndDelete(String vnfmId, String vnfId, VnfTerminateRequest request, HttpServletResponse httpResponse) {
443 logOperationInput(vnfId, "termination", request);
444 return scheduleExecution(vnfId, httpResponse, "terminateVnf", jobInfo -> {
445 terminateVnf(vnfmId, vnfId, request, jobInfo);
446 deleteVnf(vnfmId, vnfId);
453 * <li>fails if the VNF does not exist</li>
454 * <li>terminates if instantiated</li>
455 * <li>deletes the VNF</li>
458 * @param vnfmId the identifier of the VNFM
459 * @param vnfId the identifier of the VNF
460 * @param request the termination request
461 * @param httpResponse the HTTP response
462 * @return the job for polling the progress of the termination
464 public JobInfo terminate(String vnfmId, String vnfId, VnfTerminateRequest request, HttpServletResponse httpResponse) {
465 logOperationInput(vnfId, "termination", request);
466 return scheduleExecution(vnfId, httpResponse, "terminate", jobInfo -> terminateVnf(vnfmId, vnfId, request, jobInfo));
469 private void terminateVnf(String vnfmId, String vnfId, VnfTerminateRequest request, JobInfo jobInfo) {
470 TerminateVnfRequest cbamRequest = new TerminateVnfRequest();
471 setState(request, cbamRequest);
472 cbamRequest.setAdditionalParams(new Gson().toJsonTree(jobInfo).getAsJsonObject());
473 com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
474 if (vnf.getInstantiationState() == INSTANTIATED) {
475 String vimId = getVimIdFromInstantiationRequest(vnfmId, vnf);
476 grantManager.requestGrantForTerminate(vnfmId, vnfId, vimId, getVnfdIdFromModifyableAttributes(vnf), vnf, jobInfo.getJobId());
477 OperationExecution terminationOperation = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdTerminatePost(vnfId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
478 OperationExecution finishedOperation = waitForOperationToFinish(vnfmId, vnfId, terminationOperation.getId());
479 if (finishedOperation.getStatus() == FINISHED) {
480 notificationManager.waitForTerminationToBeProcessed(finishedOperation.getId());
482 throw buildFatalFailure(logger, "Unable to terminate VNF the operation did not finish with success");
485 logger.warn("The VNF with {} identifier is not instantiated no termination is required", vnfId);
489 private void setState(VnfTerminateRequest request, TerminateVnfRequest cbamRequest) {
490 if (request.getTerminationType() == null) {
491 cbamRequest.setTerminationType(TerminationType.FORCEFUL);
493 if (request.getTerminationType().equals(VnfTerminationType.GRACEFUL)) {
494 cbamRequest.setTerminationType(TerminationType.GRACEFUL);
495 cbamRequest.setGracefulTerminationTimeout(parseInt(request.getGracefulTerminationTimeout()));
497 cbamRequest.setTerminationType(TerminationType.FORCEFUL);
505 * @param vnfmId the identifier of the VNFM
506 * @param vnfId the identifier fo the VNF
508 public void deleteVnf(String vnfmId, String vnfId) {
509 logger.info("Deleting VNF with {} identifier", vnfId);
510 cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdDelete(vnfId, NOKIA_LCM_API_VERSION).blockingFirst(null);
511 logger.info("The VNF with {} identifier has been deleted", vnfId);
514 private String getVimIdFromInstantiationRequest(String vnfmId, com.nokia.cbam.lcm.v32.model.VnfInfo vnf) {
515 OperationExecution lastInstantiation = findLastInstantiation(vnf.getOperationExecutions());
516 Object operationParameters = cbamRestApiProvider.getCbamOperationExecutionApi(vnfmId).operationExecutionsOperationExecutionIdOperationParamsGet(lastInstantiation.getId(), NOKIA_LCM_API_VERSION).blockingFirst();
517 JsonObject root = new Gson().toJsonTree(operationParameters).getAsJsonObject();
518 return childElement(childElement(root, "vims").getAsJsonArray().get(0).getAsJsonObject(), "id").getAsString();
522 * @param vnfmId the identifier of the VNFM
523 * @param vnfId the identifier of the VNF
524 * @return the current state of the VNF
526 public VnfInfo queryVnf(String vnfmId, String vnfId) {
528 com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
529 return convertVnfInfo(vnfId, cbamVnfInfo);
530 } catch (Exception e) {
531 throw buildFatalFailure(logger, "Unable to query VNF (" + vnfId + ")", e);
535 private VnfInfo convertVnfInfo(String vnfId, com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo) {
536 VnfInfo vnfInfo = new VnfInfo();
537 vnfInfo.setVersion(cbamVnfInfo.getVnfSoftwareVersion());
538 vnfInfo.setVnfInstanceId(vnfId);
539 String onapCsarId = getVnfdIdFromModifyableAttributes(cbamVnfInfo);
540 vnfInfo.setVnfdId(onapCsarId);
541 vnfInfo.setVnfPackageId(onapCsarId);
542 vnfInfo.setVnfInstanceDescription(cbamVnfInfo.getDescription());
543 vnfInfo.setVnfInstanceName(cbamVnfInfo.getName());
544 vnfInfo.setVnfProvider(cbamVnfInfo.getVnfProvider());
545 vnfInfo.setVnfStatus("ACTIVE");
546 vnfInfo.setVnfType("Kuku");
550 private ScaleDirection convert(org.onap.vnfmdriver.model.ScaleDirection direction) {
551 if (org.onap.vnfmdriver.model.ScaleDirection.IN.equals(direction)) {
552 return ScaleDirection.IN;
554 return ScaleDirection.OUT;
561 * @param vnfmId the identifier of the VNFM
562 * @param vnfId the identifier of the VNF
563 * @param request the scale request
564 * @param httpResponse the HTTP response
565 * @return the job for tracking the scale
567 public JobInfo scaleVnf(String vnfmId, String vnfId, VnfScaleRequest request, HttpServletResponse httpResponse) {
568 logOperationInput(vnfId, SCALE_OPERATION_NAME, request);
569 return scheduleExecution(vnfId, httpResponse, SCALE_OPERATION_NAME, jobInfo -> {
570 ScaleVnfRequest cbamRequest = new ScaleVnfRequest();
571 cbamRequest.setAspectId(request.getAspectId());
572 cbamRequest.setNumberOfSteps(Integer.valueOf(request.getNumberOfSteps()));
573 cbamRequest.setType(convert(request.getType()));
574 com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
575 JsonObject root = new Gson().toJsonTree(jobInfo).getAsJsonObject();
576 com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
577 String vnfdContent = catalogManager.getCbamVnfdContent(vnfmId, cbamVnfInfo.getVnfdId());
578 Set<Map.Entry<String, JsonElement>> acceptableOperationParameters = getAcceptableOperationParameters(vnfdContent, "Basic", SCALE_OPERATION_NAME);
579 buildAdditionalParameters(request, root, acceptableOperationParameters);
580 cbamRequest.setAdditionalParams(root);
581 grantManager.requestGrantForScale(vnfmId, vnfId, getVimIdFromInstantiationRequest(vnfmId, vnf), getVnfdIdFromModifyableAttributes(vnf), request, jobInfo.getJobId());
582 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdScalePost(vnfId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
583 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
587 private void buildAdditionalParameters(VnfScaleRequest request, JsonObject root, Set<Map.Entry<String, JsonElement>> acceptableOperationParameters) {
588 if (request.getAdditionalParam() != null) {
589 for (Map.Entry<String, JsonElement> item : new Gson().toJsonTree(request.getAdditionalParam()).getAsJsonObject().entrySet()) {
590 if (isParameterAccepted(acceptableOperationParameters, item)) {
591 root.add(item.getKey(), item.getValue());
595 logger.warn("No additional parameters were passed for scaling");
599 private boolean isParameterAccepted(Set<Map.Entry<String, JsonElement>> acceptableOperationParameters, Map.Entry<String, JsonElement> item) {
600 boolean found = false;
601 for (Map.Entry<String, JsonElement> acceptableOperationParameter : acceptableOperationParameters) {
602 if (acceptableOperationParameter.getKey().equals(item.getKey())) {
612 * @param vnfmId the identifier of the VNFM
613 * @param vnfId the identifier of the VNF
614 * @param request the heal request
615 * @param httpResponse the HTTP response
616 * @param vnfcId the identifer of thr VNFC to be healed
617 * @return the job for tracking the heal
619 public JobInfo healVnf(String vnfmId, String vnfId, VnfHealRequest request, Optional<String> vnfcId, HttpServletResponse httpResponse) {
620 logOperationInput(vnfId, "heal", request);
621 return scheduleExecution(vnfId, httpResponse, "heal", job -> {
622 HealVnfRequest cbamHealRequest = new HealVnfRequest();
623 Map<String, String> additionalParams = new HashMap<>();
624 additionalParams.put("vmName", request.getAffectedvm().getVmname());
625 additionalParams.put("action", request.getAction());
626 additionalParams.put("jobId", job.getJobId());
627 additionalParams.put("vnfcId", vnfcId.orElse("unknown"));
628 cbamHealRequest.setAdditionalParams(additionalParams);
629 com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
630 String vimId = getVimIdFromInstantiationRequest(vnfmId, vnf);
631 grantManager.requestGrantForHeal(vnfmId, vnfId, vimId, getVnfdIdFromModifyableAttributes(vnf), request, job.getJobId());
632 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdHealPost(vnfId, cbamHealRequest, NOKIA_LCM_API_VERSION).blockingFirst();
633 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
637 public JobInfo customOperation(String vnfmId, String vnfId, String operationId, Object additionalParams, HttpServletResponse httpResponse) {
638 logOperationInput(vnfId, "custom", additionalParams);
639 return scheduleExecution(vnfId, httpResponse, "custom", job -> {
640 CustomOperationRequest cbamRequest = new CustomOperationRequest();
641 cbamRequest.setAdditionalParams(additionalParams);
642 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdCustomCustomOperationNamePost(vnfId, operationId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
643 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
647 private JobInfo scheduleExecution(String vnfId, HttpServletResponse httpResponse, String operation, AsynchronousExecution asynchronExecution) {
648 JobInfo jobInfo = new JobInfo();
649 jobInfo.setJobId(jobManager.spawnJob(vnfId, httpResponse));
650 executorService.submit(() -> {
652 asynchronExecution.execute(jobInfo);
653 } catch (RuntimeException e) {
654 logger.error("Unable to " + operation + " VNF with " + vnfId + " identifier", e);
655 jobManager.jobFinished(jobInfo.getJobId());
658 jobManager.jobFinished(jobInfo.getJobId());
663 private OperationExecution waitForOperationToFinish(String vnfmId, String vnfId, String operationExecutionId) {
666 OperationExecution operationExecution = find(cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdOperationExecutionsGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst(), opEx -> operationExecutionId.equals(opEx.getId()));
667 if (hasOperationFinished(operationExecution)) {
668 logger.debug("Operation finished with " + operationExecution.getId());
669 return operationExecution;
671 } catch (Exception e) {
672 //swallow exception and retry
673 logger.warn("Unable to retrieve operations details", e);
675 systemFunctions().sleep(OPERATION_STATUS_POLLING_INTERVAL_IN_MS);
679 private boolean hasOperationFinished(OperationExecution operationExecution) {
680 return newHashSet(FINISHED, OperationStatus.FAILED).contains(operationExecution.getStatus());
684 private interface AsynchronousExecution {
685 void execute(JobInfo job);
688 public static class VnfCreationResult {
689 private final com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo;
691 private final String vnfdId;
693 public VnfCreationResult(com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo, String vnfdId) {
694 this.vnfInfo = vnfInfo;
695 this.vnfdId = vnfdId;
698 public com.nokia.cbam.lcm.v32.model.VnfInfo getVnfInfo() {