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.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;
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;
43 import static java.lang.Integer.parseInt;
44 import static java.nio.charset.StandardCharsets.UTF_8;
45 import static java.util.stream.Collectors.toList;
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;
65 * Responsible for executing lifecycle operation on the VNF
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;
71 * The key of the CBAM VNF extension for the identifier of the VNFM in ONAP
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;
86 * Runs asynchronous operations in the background
88 private ExecutorService executorService = Executors.newCachedThreadPool();
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;
100 * @param vimId the VIM identifier
101 * @return the name of the region
103 public static String getRegionName(String vimId) {
104 return newArrayList(on(SEPARATOR).split(vimId)).get(1);
108 * @param vimId the VIM identifier
109 * @return the owner of the cloud
111 public static String getCloudOwner(String vimId) {
112 return newArrayList(on(SEPARATOR).split(vimId)).get(0);
115 private static OperationExecution findLastInstantiation(List<OperationExecution> operationExecutions) {
116 return find(NEWEST_OPERATIONS_FIRST.sortedCopy(operationExecutions), op -> INSTANTIATE.equals(op.getOperationType()));
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();
124 * Create the VNF. It consists of the following steps
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>
130 * The rollback of the failed operation is not implemented
132 * <li>delete the VNF if error occurs before instantiation</li>
133 * <li>terminateVnf & delete VNF if error occurs after instantiation</li>
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
142 public VnfCreationResult create(String vnfmId, String csarId, String vnfName, String description) {
143 logOperationInput("not yet specified", "creation", csarId);
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);
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));
165 * Instantiate the VNF
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
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)
186 response.setJobId(spawnJob.getJobId());
191 * Instantiate (VF-C terminology) the VNF. It consists of the following steps
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>
202 * The rollback of the failed operation is not implemented
204 * <li>delete the VNF if error occurs before instantiation</li>
205 * <li>terminateVnf & delete VNf if error occurs after instantiation</li>
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
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);
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);
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());
245 logger.warn("No additional parameters were specified for the operation");
247 instantiationRequest.setAdditionalParams(root);
248 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdInstantiatePost(vnfId, instantiationRequest, NOKIA_LCM_API_VERSION).blockingFirst();
249 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
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");
257 vim.setVimId(vim.getVimid());
260 if (vim.getAccessInfo() == null) {
261 if (vim.getAccessinfo() == null) {
262 throw buildFatalFailure(logger, "VF-C did not send access info in grant response");
264 vim.setAccessInfo(vim.getAccessinfo());
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);
274 return buildOpenStackV3INFO(vimId, vim, vimInfo);
277 //OTHER VIM TYPE is not possible
278 return buildVcloudInfo(vimId, vimInfo);
282 private String getVimId(Object additionalParams) {
283 return childElement(new Gson().toJsonTree(additionalParams).getAsJsonObject(), "vimId").getAsString();
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);
294 logger.info("The instantiation input for VNF with {} CSAR id does not have an " + ETSI_CONFIG + " section", csarId);
297 logger.info("The instantiation input for VNF with {} CSAR id does not have a properties section", csarId);
299 JsonObject inputs = child(root, "inputs");
300 if (!inputs.has(csarId)) {
301 return new Gson().fromJson(catalogManager.getEtsiConfiguration(csarId), AdditionalParameters.class);
303 JsonElement additionalParamsForVnf = new JsonParser().parse(inputs.get(csarId).getAsString());
304 return new Gson().fromJson(additionalParamsForVnf, AdditionalParameters.class);
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();
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();
324 throw buildFatalFailure(logger, "Unable to find operation named " + operationName);
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);
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);
356 public void executeModifyVnfInfo(String vnfmId, String vnfId, ModifyVnfInfoRequest request) {
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);
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);
373 logger.info("No extensions specified for VNF with {} identifier", vnfId);
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;
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;
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()));
413 interfaceEndpoint.setSkipCertificateHostnameCheck(true);
414 interfaceEndpoint.setSkipCertificateVerification(true);
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));
423 return interfaceEndpoint;
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);
440 * Terminates and deletes the VNF
442 * <li>fails if the VNF does not exist</li>
443 * <li>terminates if instantiated</li>
444 * <li>deletes the VNF</li>
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
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);
464 * <li>fails if the VNF does not exist</li>
465 * <li>terminates if instantiated</li>
466 * <li>deletes the VNF</li>
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
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));
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());
493 throw buildFatalFailure(logger, "Unable to terminate VNF the operation did not finish with success");
496 logger.warn("The VNF with {} identifier is not instantiated no termination is required", vnfId);
500 private void setState(VnfTerminateRequest request, TerminateVnfRequest cbamRequest) {
501 if (request.getTerminationType() == null) {
502 cbamRequest.setTerminationType(TerminationType.FORCEFUL);
504 if (request.getTerminationType().equals(VnfTerminationType.GRACEFUL)) {
505 cbamRequest.setTerminationType(TerminationType.GRACEFUL);
506 cbamRequest.setGracefulTerminationTimeout(parseInt(request.getGracefulTerminationTimeout()));
508 cbamRequest.setTerminationType(TerminationType.FORCEFUL);
516 * @param vnfmId the identifier of the VNFM
517 * @param vnfIdInVnfm the identifier fo the VNF
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);
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();
533 * @param vnfmId the identifier of the VNFM
534 * @param vnfId the identifier of the VNF
535 * @return the current state of the VNF
537 public VnfInfo queryVnf(String vnfmId, String vnfId) {
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);
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");
561 private ScaleDirection convert(org.onap.vnfmdriver.model.ScaleDirection direction) {
562 if (org.onap.vnfmdriver.model.ScaleDirection.IN.equals(direction)) {
563 return ScaleDirection.IN;
565 return ScaleDirection.OUT;
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
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());
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());
606 logger.warn("No additional parameters were passed for scaling");
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())) {
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
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());
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());
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(() -> {
663 asynchronExecution.execute(jobInfo);
664 } catch (RuntimeException e) {
665 logger.error("Unable to " + operation + " VNF with " + vnfId + " identifier", e);
666 jobManager.jobFinished(jobInfo.getJobId());
669 jobManager.jobFinished(jobInfo.getJobId());
674 private OperationExecution waitForOperationToFinish(String vnfmId, String vnfId, String operationExecutionId) {
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;
682 } catch (Exception e) {
683 //swallow exception and retry
684 logger.warn("Unable to retrieve operations details", e);
686 systemFunctions().sleep(OPERATION_STATUS_POLLING_INTERVAL_IN_MS);
690 private boolean hasOperationFinished(OperationExecution operationExecution) {
691 return newHashSet(FINISHED, OperationStatus.FAILED).contains(operationExecution.getStatus());
695 private interface AsynchronousExecution {
696 void execute(JobInfo job);
699 public static class VnfCreationResult {
700 private final com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo;
702 private final String vnfdId;
704 public VnfCreationResult(com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo, String vnfdId) {
705 this.vnfInfo = vnfInfo;
706 this.vnfdId = vnfdId;
709 public com.nokia.cbam.lcm.v32.model.VnfInfo getVnfInfo() {