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.yaml.snakeyaml.Yaml;
42 import static java.lang.Integer.parseInt;
43 import static java.nio.charset.StandardCharsets.UTF_8;
44 import static java.util.stream.Collectors.toList;
46 import static com.google.common.base.Splitter.on;
47 import static com.google.common.collect.Iterables.find;
48 import static com.google.common.collect.Iterables.transform;
49 import static com.google.common.collect.Lists.newArrayList;
50 import static com.google.common.collect.Ordering.natural;
51 import static com.google.common.collect.Sets.newHashSet;
52 import static com.nokia.cbam.lcm.v32.model.InstantiationState.INSTANTIATED;
53 import static com.nokia.cbam.lcm.v32.model.OperationStatus.FINISHED;
54 import static com.nokia.cbam.lcm.v32.model.OperationType.INSTANTIATE;
55 import static com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum.*;
56 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.CbamUtils.*;
57 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.util.SystemFunctions.systemFunctions;
58 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.CbamRestApiProvider.NOKIA_LCM_API_VERSION;
59 import static org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm.notification.LifecycleChangeNotificationManager.NEWEST_OPERATIONS_FIRST;
60 import static org.slf4j.LoggerFactory.getLogger;
61 import static org.springframework.util.StringUtils.isEmpty;
64 * Responsible for executing lifecycle operation on the VNF
66 public class LifecycleManager {
67 public static final String ONAP_CSAR_ID = "onapCsarId";
68 public static final long OPERATION_STATUS_POLLING_INTERVAL_IN_MS = 5000L;
70 * The key of the CBAM VNF extension for the identifier of the VNFM in ONAP
72 public static final String EXTERNAL_VNFM_ID = "externalVnfmId";
73 public static final String SCALE_OPERATION_NAME = "scale";
74 public static final String ETSI_CONFIG = "etsi_config";
75 public static final String PROPERTIES = "properties";
76 private static Logger logger = getLogger(LifecycleManager.class);
77 private final CatalogManager catalogManager;
78 private final IGrantManager grantManager;
79 private final JobManager jobManager;
80 private final ILifecycleChangeNotificationManager notificationManager;
81 private final CbamRestApiProvider cbamRestApiProvider;
82 private final VimInfoProvider vimInfoProvider;
85 * Runs asynchronous operations in the background
87 private ExecutorService executorService = Executors.newCachedThreadPool();
89 LifecycleManager(CatalogManager catalogManager, IGrantManager grantManager, CbamRestApiProvider restApiProvider, VimInfoProvider vimInfoProvider, JobManager jobManager, ILifecycleChangeNotificationManager notificationManager) {
90 this.vimInfoProvider = vimInfoProvider;
91 this.grantManager = grantManager;
92 this.cbamRestApiProvider = restApiProvider;
93 this.jobManager = jobManager;
94 this.notificationManager = notificationManager;
95 this.catalogManager = catalogManager;
99 * @param vimId the VIM identifier
100 * @return the name of the region
102 public static String getRegionName(String vimId) {
103 return newArrayList(on(SEPARATOR).split(vimId)).get(1);
107 * @param vimId the VIM identifier
108 * @return the owner of the cloud
110 public static String getCloudOwner(String vimId) {
111 return newArrayList(on(SEPARATOR).split(vimId)).get(0);
114 private static OperationExecution findLastInstantiation(List<OperationExecution> operationExecutions) {
115 return find(NEWEST_OPERATIONS_FIRST.sortedCopy(operationExecutions), op -> INSTANTIATE.equals(op.getOperationType()));
118 public static String getVnfdIdFromModifyableAttributes(com.nokia.cbam.lcm.v32.model.VnfInfo vnf) {
119 return find(vnf.getExtensions(), p -> p.getName().equals(ONAP_CSAR_ID)).getValue().toString();
123 * Create the VNF. It consists of the following steps
125 * <li>upload the VNF package to CBAM package (if not already there)</li>
126 * <li>create the VNF on CBAM</li>
127 * <li>modify attributes of the VNF (add onapCsarId field)</li>
129 * The rollback of the failed operation is not implemented
131 * <li>delete the VNF if error occurs before instantiation</li>
132 * <li>terminateVnf & delete VNF if error occurs after instantiation</li>
135 * @param vnfmId the identifier of the VNFM
136 * @param csarId the identifier of the VNF package
137 * @param vnfName the name of the VNF
138 * @param description the description of the VNF
139 * @return the VNF creation result
141 public VnfCreationResult create(String vnfmId, String csarId, String vnfName, String description) {
142 logOperationInput("not yet specified", "creation", csarId);
144 CatalogAdapterVnfpackage cbamPackage = catalogManager.preparePackageInCbam(vnfmId, csarId);
145 CreateVnfRequest vnfCreateRequest = new CreateVnfRequest();
146 vnfCreateRequest.setVnfdId(cbamPackage.getVnfdId());
147 vnfCreateRequest.setName(vnfName);
148 vnfCreateRequest.setDescription(description);
149 com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsPost(vnfCreateRequest, NOKIA_LCM_API_VERSION).blockingFirst();
150 addVnfdIdToVnfModifyableAttributeExtensions(vnfmId, vnfInfo.getId(), csarId);
151 return new VnfCreationResult(vnfInfo, cbamPackage.getVnfdId());
152 } catch (Exception e) {
153 throw buildFatalFailure(logger, "Unable to create the VNF", e);
157 private void logOperationInput(String vnfId, String operationName, Object payload) {
158 if (logger.isInfoEnabled()) {
159 logger.info("Starting {} operation on VNF with {} identifier with {} parameter", operationName, vnfId, new Gson().toJson(payload));
164 * Instantiate the VNF
166 * @param vnfmId the identifier of the VNFM
167 * @param externalVirtualLinks the external virtual links of the VNF
168 * @param httpResponse the HTTP response that corresponds to the VNF instantiation request
169 * @param additionalParameters additional parameters
170 * @param vnfId the identifier of the VNF
171 * @param vnfmVnfdId the identifier of the VNF package in CBAM
172 * @param operationAdditionalParameters the additional parameters of the operation
173 * @param onapVnfdId the identifier of the VNFD in the VNFM
174 * @return the instantiation response
176 @SuppressWarnings("squid:S00107") //wrapping them into an object makes the code less readable
177 public VnfInstantiateResponse instantiate(String vnfmId, List<ExtVirtualLinkInfo> externalVirtualLinks, HttpServletResponse httpResponse, Object operationAdditionalParameters, AdditionalParameters additionalParameters, String vnfId, String onapVnfdId, String vnfmVnfdId) {
178 logOperationInput(vnfId, "instantiation", additionalParameters);
179 validateVimType(additionalParameters.getVimType());
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 validateVimType(additionalParameters.getVimType());
216 VnfCreationResult creationResult = create(vnfmId, request.getVnfDescriptorId(), request.getVnfInstanceName(), request.getVnfInstanceDescription());
217 return instantiate(vnfmId, request.getExtVirtualLink(), httpResponse, request.getAdditionalParam(), additionalParameters, creationResult.vnfInfo.getId(), request.getVnfPackageId(), creationResult.vnfdId);
220 @SuppressWarnings("squid:S00107") //wrapping them into an object makes the code less readable
221 private void instantiateVnf(String vnfmId, List<ExtVirtualLinkInfo> extVirtualLinkInfos, AdditionalParameters additionalParameters, String onapVnfdId, String vnfmVnfdId, String vnfId, String vimId, JobInfo jobInfo) {
222 String vnfdContent = catalogManager.getCbamVnfdContent(vnfmId, vnfmVnfdId);
223 addSpecifiedExtensions(vnfmId, vnfId, additionalParameters);
224 GrantVNFResponseVim vim = grantManager.requestGrantForInstantiate(vnfmId, vnfId, vimId, onapVnfdId, additionalParameters.getInstantiationLevel(), vnfdContent, jobInfo.getJobId());
225 handleBackwardIncompatibleApiChangesInVfc(vim);
226 VimInfo vimInfo = vimInfoProvider.getVimInfo(vim.getVimId());
227 InstantiateVnfRequest instantiationRequest = new InstantiateVnfRequest();
228 addExternalLinksToRequest(extVirtualLinkInfos, additionalParameters, instantiationRequest, vimId);
229 instantiationRequest.getVims().add(addVim(additionalParameters, vimId, vim, vimInfo));
230 instantiationRequest.setFlavourId(getFlavorId(vnfdContent));
231 instantiationRequest.setComputeResourceFlavours(additionalParameters.getComputeResourceFlavours());
232 instantiationRequest.setGrantlessMode(true);
233 instantiationRequest.setInstantiationLevelId(additionalParameters.getInstantiationLevel());
234 instantiationRequest.setSoftwareImages(additionalParameters.getSoftwareImages());
235 instantiationRequest.setZones(additionalParameters.getZones());
236 instantiationRequest.setExtManagedVirtualLinks(additionalParameters.getExtManagedVirtualLinks());
237 for (ExtVirtualLinkData extVirtualLinkData : additionalParameters.getExtVirtualLinks()) {
238 instantiationRequest.addExtVirtualLinksItem(extVirtualLinkData);
240 JsonObject root = new Gson().toJsonTree(jobInfo).getAsJsonObject();
241 if (additionalParameters.getAdditionalParams() != null) {
242 for (Map.Entry<String, JsonElement> item : new Gson().toJsonTree(additionalParameters.getAdditionalParams()).getAsJsonObject().entrySet()) {
243 root.add(item.getKey(), item.getValue());
246 logger.warn("No additional parameters were specified for the operation");
248 instantiationRequest.setAdditionalParams(root);
249 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdInstantiatePost(vnfId, instantiationRequest, NOKIA_LCM_API_VERSION).blockingFirst();
250 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
253 private void handleBackwardIncompatibleApiChangesInVfc(GrantVNFResponseVim vim) {
254 if (vim.getVimId() == null) {
255 if (vim.getVimid() == null) {
256 throw buildFatalFailure(logger, "VF-C did not send VIM identifier in grant response");
258 vim.setVimId(vim.getVimid());
261 if (vim.getAccessInfo() == null) {
262 if (vim.getAccessinfo() == null) {
263 throw buildFatalFailure(logger, "VF-C did not send access info in grant response");
265 vim.setAccessInfo(vim.getAccessinfo());
270 private com.nokia.cbam.lcm.v32.model.VimInfo addVim(AdditionalParameters additionalParameters, String vimId, GrantVNFResponseVim vim, VimInfo vimInfo) {
271 if (additionalParameters.getVimType() == OPENSTACK_V2_INFO) {
272 return buildOpenStackV2INFO(vimId, vim, vimInfo);
274 } else if (additionalParameters.getVimType() == OPENSTACK_V3_INFO) {
275 if (isEmpty(vimInfo.getDomain())) {
276 if (isEmpty(additionalParameters.getDomain())) {
277 throw buildFatalFailure(logger, "The cloud did not supply the cloud domain (Amsterdam release) and was not supplied as additional data");
279 logger.warn("Setting domain from additional parameters");
280 vimInfo.setDomain(additionalParameters.getDomain());
283 return buildOpenStackV3INFO(vimId, vim, vimInfo);
285 //OTHER VIM TYPE is not possible
286 return buildVcloudInfo(vimId, vimInfo);
290 private void validateVimType(com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum vimType) {
291 if (com.nokia.cbam.lcm.v32.model.VimInfo.VimInfoTypeEnum.OTHER_VIM_INFO.equals(vimType)) {
292 throw buildFatalFailure(logger, "Only " + OPENSTACK_V2_INFO + ", " + OPENSTACK_V3_INFO + " and " + VMWARE_VCLOUD_INFO + " is the supported VIM types");
296 private String getVimId(Object additionalParams) {
297 return childElement(new Gson().toJsonTree(additionalParams).getAsJsonObject(), "vimId").getAsString();
300 private AdditionalParameters convertInstantiationAdditionalParams(String csarId, Object additionalParams) {
301 JsonObject root = new Gson().toJsonTree(additionalParams).getAsJsonObject();
302 if (root.has(PROPERTIES)) {
303 JsonObject properties = new JsonParser().parse(root.get(PROPERTIES).getAsString()).getAsJsonObject();
304 if (properties.has(ETSI_CONFIG)) {
305 JsonElement etsiConfig = properties.get(ETSI_CONFIG);
306 return new Gson().fromJson(etsiConfig.getAsString(), AdditionalParameters.class);
308 logger.info("The instantiation input for VNF with {} CSAR id does not have an " + ETSI_CONFIG + " section", csarId);
311 logger.info("The instantiation input for VNF with {} CSAR id does not have a properties section", csarId);
313 JsonObject inputs = child(root, "inputs");
314 if (!inputs.has(csarId)) {
315 return new Gson().fromJson(catalogManager.getEtsiConfiguration(csarId), AdditionalParameters.class);
317 JsonElement additionalParamsForVnf = new JsonParser().parse(inputs.get(csarId).getAsString());
318 return new Gson().fromJson(additionalParamsForVnf, AdditionalParameters.class);
321 private String getFlavorId(String vnfdContent) {
322 JsonObject root = new Gson().toJsonTree(new Yaml().load(vnfdContent)).getAsJsonObject();
323 JsonObject capabilities = child(child(child(root, "topology_template"), "substitution_mappings"), "capabilities");
324 JsonObject deploymentFlavorProperties = child(child(capabilities, "deployment_flavour"), PROPERTIES);
325 return childElement(deploymentFlavorProperties, "flavour_id").getAsString();
328 private Set<Map.Entry<String, JsonElement>> getAcceptableOperationParameters(String vnfdContent, String operationName) {
329 JsonObject root = new Gson().toJsonTree(new Yaml().load(vnfdContent)).getAsJsonObject();
330 JsonObject interfaces = child(child(child(root, "topology_template"), "substitution_mappings"), "interfaces");
331 List<List<Map.Entry<String, JsonElement>>> operations = interfaces.entrySet().stream().map(m -> m.getValue().getAsJsonObject().entrySet().stream().collect(toList())).collect(toList());
332 for (Map.Entry<String, JsonElement> operation : operations.stream().flatMap(List::stream).collect(toList())) {
333 if (operation.getKey().equals(operationName)) {
334 return child(child(operation.getValue().getAsJsonObject(), "inputs"), "additional_parameters").entrySet();
338 throw buildFatalFailure(logger, "Unable to find operation named " + operationName);
341 private void addExternalLinksToRequest(List<ExtVirtualLinkInfo> extVirtualLinks, AdditionalParameters additionalParameters, InstantiateVnfRequest instantiationRequest, String vimId) {
342 for (ExtVirtualLinkInfo extVirtualLink : extVirtualLinks) {
343 ExtVirtualLinkData cbamExternalVirtualLink = new ExtVirtualLinkData();
344 cbamExternalVirtualLink.setVimId(vimId);
345 cbamExternalVirtualLink.setResourceId(extVirtualLink.getResourceId());
346 VnfExtCpData ecp = new VnfExtCpData();
347 cbamExternalVirtualLink.setExtVirtualLinkId(extVirtualLink.getVlInstanceId());
348 cbamExternalVirtualLink.getExtCps().add(ecp);
349 ecp.setCpdId(extVirtualLink.getCpdId());
350 List<NetworkAddress> addresses = additionalParameters.getExternalConnectionPointAddresses().get(extVirtualLink.getCpdId());
351 ecp.setAddresses(addresses);
352 instantiationRequest.addExtVirtualLinksItem(cbamExternalVirtualLink);
356 private void addVnfdIdToVnfModifyableAttributeExtensions(String vnfmId, String vnfId, String onapCsarId) {
357 ModifyVnfInfoRequest request = new ModifyVnfInfoRequest();
358 request.setExtensions(new ArrayList<>());
359 VnfProperty onapCsarIdProperty = new VnfProperty();
360 onapCsarIdProperty.setName(ONAP_CSAR_ID);
361 onapCsarIdProperty.setValue(onapCsarId);
362 request.getExtensions().add(onapCsarIdProperty);
363 VnfProperty externalVnfmIdProperty = new VnfProperty();
364 externalVnfmIdProperty.setName(EXTERNAL_VNFM_ID);
365 externalVnfmIdProperty.setValue(vnfmId);
366 request.getExtensions().add(externalVnfmIdProperty);
367 executeModifyVnfInfo(vnfmId, vnfId, request);
370 private void executeModifyVnfInfo(String vnfmId, String vnfId, ModifyVnfInfoRequest request) {
372 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdPatch(vnfId, request, NOKIA_LCM_API_VERSION).blockingFirst();
373 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
374 } catch (Exception e) {
375 String properties = Joiner.on(",").join(natural().sortedCopy(transform(request.getExtensions(), VnfProperty::getName)));
376 throw buildFatalFailure(logger, "Unable to set the " + properties + " properties on the VNF with " + vnfId + " identifier", e);
380 private void addSpecifiedExtensions(String vnfmId, String vnfId, AdditionalParameters additionalParameters) {
381 if (!additionalParameters.getExtensions().isEmpty()) {
382 ModifyVnfInfoRequest request = new ModifyVnfInfoRequest();
383 request.setExtensions(new ArrayList<>());
384 request.getExtensions().addAll(additionalParameters.getExtensions());
385 executeModifyVnfInfo(vnfmId, vnfId, request);
387 logger.info("No extensions specified for VNF with {} identifier", vnfId);
391 private OPENSTACKV3INFO buildOpenStackV3INFO(String vimId, GrantVNFResponseVim vim, org.onap.vnfmdriver.model.VimInfo vimInfo) {
392 OPENSTACKV3INFO openstackv3INFO = new OPENSTACKV3INFO();
393 openstackv3INFO.setVimInfoType(OPENSTACK_V3_INFO);
394 OpenStackAccessInfoV3 accessInfov3 = new OpenStackAccessInfoV3();
395 openstackv3INFO.accessInfo(accessInfov3);
396 accessInfov3.setPassword(vimInfo.getPassword());
397 accessInfov3.setDomain(vimInfo.getDomain());
398 accessInfov3.setProject(vim.getAccessInfo().getTenant());
399 accessInfov3.setRegion(getRegionName(vimId));
400 accessInfov3.setUsername(vimInfo.getUserName());
401 openstackv3INFO.setInterfaceInfo(getEndpointInfo(vimInfo));
402 openstackv3INFO.setId(vimId);
403 return openstackv3INFO;
406 private OPENSTACKV2INFO buildOpenStackV2INFO(String vimId, GrantVNFResponseVim vim, org.onap.vnfmdriver.model.VimInfo vimInfo) {
407 OPENSTACKV2INFO openstackv2INFO = new OPENSTACKV2INFO();
408 openstackv2INFO.setVimInfoType(OPENSTACK_V2_INFO);
409 OpenStackAccessInfoV2 accessInfo = new OpenStackAccessInfoV2();
410 openstackv2INFO.setAccessInfo(accessInfo);
411 accessInfo.setPassword(vimInfo.getPassword());
412 accessInfo.setTenant(vim.getAccessInfo().getTenant());
413 accessInfo.setUsername(vimInfo.getUserName());
414 accessInfo.setRegion(getRegionName(vimId));
415 EndpointInfo interfaceEndpoint = getEndpointInfo(vimInfo);
416 openstackv2INFO.setInterfaceInfo(interfaceEndpoint);
417 openstackv2INFO.setId(vimId);
418 return openstackv2INFO;
421 private EndpointInfo getEndpointInfo(VimInfo vimInfo) {
422 EndpointInfo interfaceEndpoint = new EndpointInfo();
423 if (!isEmpty(vimInfo.getSslInsecure())) {
424 interfaceEndpoint.setSkipCertificateHostnameCheck(Boolean.parseBoolean(vimInfo.getSslInsecure()));
425 interfaceEndpoint.setSkipCertificateVerification(Boolean.parseBoolean(vimInfo.getSslInsecure()));
427 interfaceEndpoint.setSkipCertificateHostnameCheck(true);
428 interfaceEndpoint.setSkipCertificateVerification(true);
430 interfaceEndpoint.setEndpoint(vimInfo.getUrl());
431 if (!interfaceEndpoint.isSkipCertificateVerification()) {
432 interfaceEndpoint.setTrustedCertificates(new ArrayList<>());
433 for (String trustedCertificate : StoreLoader.getCertifacates(vimInfo.getSslCacert())) {
434 interfaceEndpoint.getTrustedCertificates().add(trustedCertificate.getBytes(UTF_8));
437 return interfaceEndpoint;
440 private VMWAREVCLOUDINFO buildVcloudInfo(String vimId, org.onap.vnfmdriver.model.VimInfo vimInfo) {
441 VMWAREVCLOUDINFO vcloudInfo = new VMWAREVCLOUDINFO();
442 vcloudInfo.setVimInfoType(VMWARE_VCLOUD_INFO);
443 VCloudAccessInfo accessInfo = new VCloudAccessInfo();
444 vcloudInfo.setAccessInfo(accessInfo);
445 accessInfo.setPassword(vimInfo.getPassword());
446 accessInfo.setUsername(vimInfo.getUserName());
447 accessInfo.setOrganization(getRegionName(vimId));
448 vcloudInfo.setInterfaceInfo(getEndpointInfo(vimInfo));
449 vcloudInfo.setId(vimId);
454 * Terminates and deletes the VNF
456 * <li>fails if the VNF does not exist</li>
457 * <li>terminates if instantiated</li>
458 * <li>deletes the VNF</li>
461 * @param vnfmId the identifier of the VNFM
462 * @param vnfId the identifier of the VNF
463 * @param request the termination request
464 * @param httpResponse the HTTP response
465 * @return the job for polling the progress of the termination
467 public JobInfo terminateAndDelete(String vnfmId, String vnfId, VnfTerminateRequest request, HttpServletResponse httpResponse) {
468 logOperationInput(vnfId, "termination", request);
469 return scheduleExecution(vnfId, httpResponse, "terminateVnf", jobInfo -> {
470 terminateVnf(vnfmId, vnfId, request, jobInfo);
471 deleteVnf(vnfmId, vnfId);
478 * <li>fails if the VNF does not exist</li>
479 * <li>terminates if instantiated</li>
480 * <li>deletes the VNF</li>
483 * @param vnfmId the identifier of the VNFM
484 * @param vnfId the identifier of the VNF
485 * @param request the termination request
486 * @param httpResponse the HTTP response
487 * @return the job for polling the progress of the termination
489 public JobInfo terminate(String vnfmId, String vnfId, VnfTerminateRequest request, HttpServletResponse httpResponse) {
490 logOperationInput(vnfId, "termination", request);
491 return scheduleExecution(vnfId, httpResponse, "terminate", jobInfo -> terminateVnf(vnfmId, vnfId, request, jobInfo));
494 private void terminateVnf(String vnfmId, String vnfId, VnfTerminateRequest request, JobInfo jobInfo) {
495 TerminateVnfRequest cbamRequest = new TerminateVnfRequest();
496 setState(request, cbamRequest);
497 cbamRequest.setAdditionalParams(new Gson().toJsonTree(jobInfo).getAsJsonObject());
498 com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
499 if (vnf.getInstantiationState() == INSTANTIATED) {
500 String vimId = getVimIdFromInstantiationRequest(vnfmId, vnf);
501 grantManager.requestGrantForTerminate(vnfmId, vnfId, vimId, getVnfdIdFromModifyableAttributes(vnf), vnf, jobInfo.getJobId());
502 OperationExecution terminationOperation = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdTerminatePost(vnfId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
503 OperationExecution finishedOperation = waitForOperationToFinish(vnfmId, vnfId, terminationOperation.getId());
504 if (finishedOperation.getStatus() == FINISHED) {
505 notificationManager.waitForTerminationToBeProcessed(finishedOperation.getId());
507 throw buildFatalFailure(logger, "Unable to terminate VNF the operation did not finish with success");
510 logger.warn("The VNF with {} identifier is not instantiated no termination is required", vnfId);
514 private void setState(VnfTerminateRequest request, TerminateVnfRequest cbamRequest) {
515 if (request.getTerminationType() == null) {
516 cbamRequest.setTerminationType(TerminationType.FORCEFUL);
518 if (request.getTerminationType().equals(VnfTerminationType.GRACEFUL)) {
519 cbamRequest.setTerminationType(TerminationType.GRACEFUL);
520 cbamRequest.setGracefulTerminationTimeout(parseInt(request.getGracefulTerminationTimeout()));
522 cbamRequest.setTerminationType(TerminationType.FORCEFUL);
530 * @param vnfmId the identifier of the VNFM
531 * @param vnfId the identifier fo the VNF
533 public void deleteVnf(String vnfmId, String vnfId) {
534 logger.info("Deleting VNF with {} identifier", vnfId);
535 cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdDelete(vnfId, NOKIA_LCM_API_VERSION).blockingFirst(null);
536 logger.info("The VNF with {} identifier has been deleted", vnfId);
539 private String getVimIdFromInstantiationRequest(String vnfmId, com.nokia.cbam.lcm.v32.model.VnfInfo vnf) {
540 OperationExecution lastInstantiation = findLastInstantiation(vnf.getOperationExecutions());
541 Object operationParameters = cbamRestApiProvider.getCbamOperationExecutionApi(vnfmId).operationExecutionsOperationExecutionIdOperationParamsGet(lastInstantiation.getId(), NOKIA_LCM_API_VERSION).blockingFirst();
542 JsonObject root = new Gson().toJsonTree(operationParameters).getAsJsonObject();
543 return childElement(childElement(root, "vims").getAsJsonArray().get(0).getAsJsonObject(), "id").getAsString();
547 * @param vnfmId the identifier of the VNFM
548 * @param vnfId the identifier of the VNF
549 * @return the current state of the VNF
551 public VnfInfo queryVnf(String vnfmId, String vnfId) {
553 com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
554 return convertVnfInfo(vnfId, cbamVnfInfo);
555 } catch (Exception e) {
556 throw buildFatalFailure(logger, "Unable to query VNF (" + vnfId + ")", e);
560 private VnfInfo convertVnfInfo(String vnfId, com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo) {
561 VnfInfo vnfInfo = new VnfInfo();
562 vnfInfo.setVersion(cbamVnfInfo.getVnfSoftwareVersion());
563 vnfInfo.setVnfInstanceId(vnfId);
564 String onapCsarId = getVnfdIdFromModifyableAttributes(cbamVnfInfo);
565 vnfInfo.setVnfdId(onapCsarId);
566 vnfInfo.setVnfPackageId(onapCsarId);
567 vnfInfo.setVnfInstanceDescription(cbamVnfInfo.getDescription());
568 vnfInfo.setVnfInstanceName(cbamVnfInfo.getName());
569 vnfInfo.setVnfProvider(cbamVnfInfo.getVnfProvider());
570 vnfInfo.setVnfStatus("ACTIVE");
571 vnfInfo.setVnfType("Kuku");
575 private ScaleDirection convert(org.onap.vnfmdriver.model.ScaleDirection direction) {
576 if (org.onap.vnfmdriver.model.ScaleDirection.IN.equals(direction)) {
577 return ScaleDirection.IN;
579 return ScaleDirection.OUT;
586 * @param vnfmId the identifier of the VNFM
587 * @param vnfId the identifier of the VNF
588 * @param request the scale request
589 * @param httpResponse the HTTP response
590 * @return the job for tracking the scale
592 public JobInfo scaleVnf(String vnfmId, String vnfId, VnfScaleRequest request, HttpServletResponse httpResponse) {
593 logOperationInput(vnfId, SCALE_OPERATION_NAME, request);
594 return scheduleExecution(vnfId, httpResponse, SCALE_OPERATION_NAME, jobInfo -> {
595 ScaleVnfRequest cbamRequest = new ScaleVnfRequest();
596 cbamRequest.setAspectId(request.getAspectId());
597 cbamRequest.setNumberOfSteps(Integer.valueOf(request.getNumberOfSteps()));
598 cbamRequest.setType(convert(request.getType()));
599 com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
600 JsonObject root = new Gson().toJsonTree(jobInfo).getAsJsonObject();
601 com.nokia.cbam.lcm.v32.model.VnfInfo cbamVnfInfo = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
602 String vnfdContent = catalogManager.getCbamVnfdContent(vnfmId, cbamVnfInfo.getVnfdId());
603 Set<Map.Entry<String, JsonElement>> acceptableOperationParameters = getAcceptableOperationParameters(vnfdContent, SCALE_OPERATION_NAME);
604 buildAdditionalParameters(request, root, acceptableOperationParameters);
605 cbamRequest.setAdditionalParams(root);
606 grantManager.requestGrantForScale(vnfmId, vnfId, getVimIdFromInstantiationRequest(vnfmId, vnf), getVnfdIdFromModifyableAttributes(vnf), request, jobInfo.getJobId());
607 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdScalePost(vnfId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
608 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
612 private void buildAdditionalParameters(VnfScaleRequest request, JsonObject root, Set<Map.Entry<String, JsonElement>> acceptableOperationParameters) {
613 if (request.getAdditionalParam() != null) {
614 for (Map.Entry<String, JsonElement> item : new Gson().toJsonTree(request.getAdditionalParam()).getAsJsonObject().entrySet()) {
615 if (isParameterAccepted(acceptableOperationParameters, item)) {
616 root.add(item.getKey(), item.getValue());
620 logger.warn("No additional parameters were passed for scaling");
624 private boolean isParameterAccepted(Set<Map.Entry<String, JsonElement>> acceptableOperationParameters, Map.Entry<String, JsonElement> item) {
625 boolean found = false;
626 for (Map.Entry<String, JsonElement> acceptableOperationParameter : acceptableOperationParameters) {
627 if (acceptableOperationParameter.getKey().equals(item.getKey())) {
637 * @param vnfmId the identifier of the VNFM
638 * @param vnfId the identifier of the VNF
639 * @param request the heal request
640 * @param httpResponse the HTTP response
641 * @param vnfcId the identifer of thr VNFC to be healed
642 * @return the job for tracking the heal
644 public JobInfo healVnf(String vnfmId, String vnfId, VnfHealRequest request, Optional<String> vnfcId, HttpServletResponse httpResponse) {
645 logOperationInput(vnfId, "heal", request);
646 return scheduleExecution(vnfId, httpResponse, "heal", job -> {
647 HealVnfRequest cbamHealRequest = new HealVnfRequest();
648 Map<String, String> additionalParams = new HashMap<>();
649 additionalParams.put("vmName", request.getAffectedvm().getVmname());
650 additionalParams.put("action", request.getAction());
651 additionalParams.put("jobId", job.getJobId());
652 additionalParams.put("vnfcId", vnfcId.orElse("unknown"));
653 cbamHealRequest.setAdditionalParams(additionalParams);
654 com.nokia.cbam.lcm.v32.model.VnfInfo vnf = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst();
655 String vimId = getVimIdFromInstantiationRequest(vnfmId, vnf);
656 grantManager.requestGrantForHeal(vnfmId, vnfId, vimId, getVnfdIdFromModifyableAttributes(vnf), request, job.getJobId());
657 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdHealPost(vnfId, cbamHealRequest, NOKIA_LCM_API_VERSION).blockingFirst();
658 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
662 public JobInfo customOperation(String vnfmId, String vnfId, String operationId, Object additionalParams, HttpServletResponse httpResponse) {
663 logOperationInput(vnfId, "custom", additionalParams);
664 return scheduleExecution(vnfId, httpResponse, "custom", job -> {
665 CustomOperationRequest cbamRequest = new CustomOperationRequest();
666 cbamRequest.setAdditionalParams(additionalParams);
667 OperationExecution operationExecution = cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdCustomCustomOperationNamePost(vnfId, operationId, cbamRequest, NOKIA_LCM_API_VERSION).blockingFirst();
668 waitForOperationToFinish(vnfmId, vnfId, operationExecution.getId());
672 private JobInfo scheduleExecution(String vnfId, HttpServletResponse httpResponse, String operation, AsynchronousExecution asynchronExecution) {
673 JobInfo jobInfo = new JobInfo();
674 jobInfo.setJobId(jobManager.spawnJob(vnfId, httpResponse));
675 executorService.submit(() -> {
677 asynchronExecution.execute(jobInfo);
678 } catch (RuntimeException e) {
679 logger.error("Unable to " + operation + " VNF with " + vnfId + " identifier", e);
680 jobManager.jobFinished(jobInfo.getJobId());
683 jobManager.jobFinished(jobInfo.getJobId());
688 private OperationExecution waitForOperationToFinish(String vnfmId, String vnfId, String operationExecutionId) {
691 OperationExecution operationExecution = find(cbamRestApiProvider.getCbamLcmApi(vnfmId).vnfsVnfInstanceIdOperationExecutionsGet(vnfId, NOKIA_LCM_API_VERSION).blockingFirst(), opEx -> operationExecutionId.equals(opEx.getId()));
692 if (hasOperationFinished(operationExecution)) {
693 logger.debug("Operation finished with " + operationExecution.getId());
694 return operationExecution;
696 } catch (Exception e) {
697 //swallow exception and retry
698 logger.warn("Unable to retrieve operations details", e);
700 systemFunctions().sleep(OPERATION_STATUS_POLLING_INTERVAL_IN_MS);
704 private boolean hasOperationFinished(OperationExecution operationExecution) {
705 return newHashSet(FINISHED, OperationStatus.FAILED).contains(operationExecution.getStatus());
709 private interface AsynchronousExecution {
710 void execute(JobInfo job);
713 public static class VnfCreationResult {
714 private final com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo;
716 private final String vnfdId;
718 public VnfCreationResult(com.nokia.cbam.lcm.v32.model.VnfInfo vnfInfo, String vnfdId) {
719 this.vnfInfo = vnfInfo;
720 this.vnfdId = vnfdId;
723 public com.nokia.cbam.lcm.v32.model.VnfInfo getVnfInfo() {