1 package org.onap.so.svnfm.simulator.services;
3 import com.google.gson.JsonObject;
4 import com.google.gson.JsonParser;
5 import org.apache.commons.codec.binary.Base64;
6 import org.modelmapper.ModelMapper;
7 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiResponse;
8 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.InlineResponse201;
9 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.*;
10 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.ApiClient;
11 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.ApiException;
12 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.api.DefaultApi;
13 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs;
14 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.ChangeTypeEnum;
15 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinks;
16 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance;
17 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification;
18 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.NotificationStatusEnum;
19 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.NotificationTypeEnum;
20 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationEnum;
21 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum;
22 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.*;
23 import org.onap.so.svnfm.simulator.api.VeVnfmApi;
24 import org.onap.so.svnfm.simulator.config.ApplicationConfig;
25 import org.onap.so.svnfm.simulator.model.VnfOperation;
26 import org.onap.so.svnfm.simulator.model.Vnfds;
27 import org.onap.so.svnfm.simulator.repository.VnfOperationRepository;
28 import org.onap.so.svnfm.simulator.util.PatternContainedChecker;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.core.io.ClassPathResource;
32 import org.springframework.core.io.Resource;
34 import javax.net.ssl.HttpsURLConnection;
35 import javax.net.ssl.KeyManager;
36 import javax.net.ssl.KeyManagerFactory;
37 import javax.ws.rs.core.MediaType;
38 import java.io.BufferedReader;
39 import java.io.IOException;
40 import java.io.InputStream;
41 import java.io.InputStreamReader;
43 import java.nio.charset.StandardCharsets;
44 import java.security.KeyStore;
45 import java.security.KeyStoreException;
46 import java.security.NoSuchAlgorithmException;
47 import java.security.UnrecoverableKeyException;
48 import java.security.cert.CertificateException;
51 public abstract class OperationProgressor implements Runnable {
53 private static final Logger LOGGER = LoggerFactory.getLogger(OperationProgressor.class);
54 private static final String CERTIFICATE_TO_TRUST = "so-vnfm-adapter.crt.pem";
55 protected final VnfOperation operation;
56 protected final SvnfmService svnfmService;
57 protected final Vnfds vnfds;
58 private final VnfOperationRepository vnfOperationRepository;
59 private final ApplicationConfig applicationConfig;
60 private final SubscriptionService subscriptionService;
61 private final DefaultApi notificationClient;
62 private final org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.api.DefaultApi grantClient;
63 private final Resource keyStoreResource = new ClassPathResource("so-vnfm-simulator.p12");
64 private final String keyStorePassword = "7Em3&j4.19xYiMelhD5?xbQ.";
66 public OperationProgressor(final VnfOperation operation, final SvnfmService svnfmService,
67 final VnfOperationRepository vnfOperationRepository, final ApplicationConfig applicationConfig,
68 final Vnfds vnfds, final SubscriptionService subscriptionService) {
69 this.operation = operation;
70 this.svnfmService = svnfmService;
71 this.vnfOperationRepository = vnfOperationRepository;
72 this.applicationConfig = applicationConfig;
74 this.subscriptionService = subscriptionService;
76 final ApiClient apiClient = new ApiClient();
77 String callBackUrl = getLastLccnSubscriptionRequest().getCallbackUri();
78 final PatternContainedChecker checker = new PatternContainedChecker("/lcn/", callBackUrl);
79 callBackUrl = checker.getText();
80 apiClient.setBasePath(callBackUrl);
81 apiClient.setKeyManagers(getKeyManagers());
82 apiClient.setSslCaCert(getCertificateToTrust());
83 notificationClient = checker.isContained() ? new DefaultApi(apiClient) : new VeVnfmApi(apiClient);
85 final org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiClient grantApiClient =
86 new org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiClient();
87 grantApiClient.setBasePath(callBackUrl);
88 grantApiClient.setKeyManagers(getKeyManagers());
89 grantApiClient.setSslCaCert(getCertificateToTrust());
90 grantClient = new org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.api.DefaultApi(grantApiClient);
93 private InputStream getCertificateToTrust() {
95 return new ClassPathResource(CERTIFICATE_TO_TRUST).getInputStream();
96 } catch (final IOException exception) {
97 LOGGER.error("Error reading certificate to trust, https calls to VNFM adapter will fail", exception);
102 private KeyManager[] getKeyManagers() {
105 keystore = KeyStore.getInstance("pkcs12");
106 keystore.load(keyStoreResource.getInputStream(), keyStorePassword.toCharArray());
107 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
108 keyManagerFactory.init(keystore, keyStorePassword.toCharArray());
109 return keyManagerFactory.getKeyManagers();
110 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException
111 | UnrecoverableKeyException exception) {
112 LOGGER.error("Error reading certificate, https calls using two way TLS to VNFM adapter will fail",
114 return new KeyManager[0];
121 final VnfLcmOperationOccurrenceNotification notificationOfStarting =
122 buildNotification(NotificationStatusEnum.START, OperationStateEnum.STARTING);
123 sendNotification(notificationOfStarting);
126 setState(InlineResponse200.OperationStateEnum.PROCESSING);
127 final VnfLcmOperationOccurrenceNotification notificationOfProcessing =
128 buildNotification(NotificationStatusEnum.START, OperationStateEnum.PROCESSING);
129 sendNotification(notificationOfProcessing);
131 final GrantRequest grantRequest = buildGrantRequest();
132 final InlineResponse201 grantResponse = sendGrantRequest(grantRequest);
133 final List<InlineResponse201InstantiatedVnfInfoVnfcResourceInfo> vnfcs = handleGrantResponse(grantResponse);
135 svnfmService.getVnf(operation.getVnfInstanceId()).getInstantiatedVnfInfo();
138 setState(InlineResponse200.OperationStateEnum.COMPLETED);
139 final VnfLcmOperationOccurrenceNotification notificationOfCompleted =
140 buildNotification(NotificationStatusEnum.RESULT, OperationStateEnum.COMPLETED);
141 notificationOfCompleted.setAffectedVnfcs(getVnfcs(vnfcs));
143 sendNotification(notificationOfCompleted);
144 } catch (final Exception exception) {
145 LOGGER.error("Error in OperationProgressor ", exception);
149 private void sleep(final long milliSeconds) {
151 Thread.sleep(milliSeconds);
152 } catch (final InterruptedException e) {
153 operation.setOperationState(InlineResponse200.OperationStateEnum.FAILED);
154 // Restore interrupted state
155 Thread.currentThread().interrupt();
159 private void setState(final InlineResponse200.OperationStateEnum state) {
160 LOGGER.info("Setting state to {} for operation {}", state, operation.getId());
161 operation.setOperationState(state);
162 vnfOperationRepository.save(operation);
165 private VnfLcmOperationOccurrenceNotification buildNotification(final NotificationStatusEnum status,
166 final OperationStateEnum operationState) {
167 final VnfLcmOperationOccurrenceNotification notification = new VnfLcmOperationOccurrenceNotification();
168 notification.setId(UUID.randomUUID().toString());
169 notification.setNotificationType(NotificationTypeEnum.VNFLCMOPERATIONOCCURRENCENOTIFICATION);
170 notification.setNotificationStatus(status);
171 notification.setOperationState(operationState);
172 notification.setOperation(OperationEnum.fromValue(operation.getOperation().toString()));
173 notification.setVnfInstanceId(operation.getVnfInstanceId());
174 notification.setVnfLcmOpOccId(operation.getId());
176 final LcnVnfLcmOperationOccurrenceNotificationLinks links = new LcnVnfLcmOperationOccurrenceNotificationLinks();
177 final LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance vnfInstanceLink =
178 new LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance();
179 vnfInstanceLink.setHref(getVnfLink());
180 links.setVnfInstance(vnfInstanceLink);
182 final LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance operationLink =
183 new LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance();
184 operationLink.setHref(getOperationLink());
185 links.setVnfLcmOpOcc(operationLink);
187 notification.setLinks(links);
192 private List<LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs> getVnfcs(
193 final List<InlineResponse201InstantiatedVnfInfoVnfcResourceInfo> instantiatedVnfcs) {
194 final List<LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs> vnfcs = new ArrayList<>();
195 if (instantiatedVnfcs != null) {
196 for (final InlineResponse201InstantiatedVnfInfoVnfcResourceInfo instantiatedVnfc : instantiatedVnfcs) {
197 LOGGER.info("VNFC TO BE CONVERTED: {}", instantiatedVnfc);
198 final ModelMapper mapper = new ModelMapper();
199 final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc =
200 mapper.map(instantiatedVnfc, LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.class);
201 LOGGER.info("VNFC FROM CONVERSION: {}", vnfc);
202 vnfc.setChangeType(getVnfcChangeType());
209 private void sendNotification(final VnfLcmOperationOccurrenceNotification notification) {
210 LOGGER.info("Sending notification: {}", notification);
212 final SubscriptionsAuthenticationParamsBasic subscriptionAuthentication =
213 getLastLccnSubscriptionRequest().getAuthentication().getParamsBasic();
214 final String auth = subscriptionAuthentication.getUserName() + ":" + subscriptionAuthentication.getPassword();
215 final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
216 String authHeader = "Basic " + new String(encodedAuth);
217 notificationClient.lcnVnfLcmOperationOccurrenceNotificationPostWithHttpInfo(notification, MediaType.APPLICATION_JSON, authHeader);
218 } catch (final ApiException exception) {
219 LOGGER.error("Error sending notification: " + notification, exception);
220 LOGGER.error("Response code: {}, body: {}, basePath: {}", exception.getCode(), exception.getResponseBody(),
221 notificationClient.getApiClient().getBasePath());
225 public GrantRequest buildGrantRequest() {
226 final GrantRequest grantRequest = new GrantRequest();
227 grantRequest.setVnfInstanceId(operation.getVnfInstanceId());
228 final String vnfdId = svnfmService.getVnf(operation.getVnfInstanceId()).getVnfdId();
229 grantRequest.setVnfdId(vnfdId);
230 grantRequest.setAddResources(getAddResources(vnfdId));
231 grantRequest.setRemoveResources(getRemoveResources(vnfdId));
232 grantRequest.setVnfLcmOpOccId(operation.getId());
234 .setOperation(org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.GrantRequest.OperationEnum
235 .fromValue(operation.getOperation().getValue()));
236 grantRequest.setIsAutomaticInvocation(false);
238 final GrantsLinksVnfLcmOpOcc vnfInstanceLink = new GrantsLinksVnfLcmOpOcc();
239 vnfInstanceLink.setHref(getVnfLink());
240 final GrantsLinksVnfLcmOpOcc operationInstanceLink = new GrantsLinksVnfLcmOpOcc();
241 operationInstanceLink.setHref(getOperationLink());
242 final GrantsLinks links = new GrantsLinks();
243 links.setVnfInstance(vnfInstanceLink);
244 links.setVnfLcmOpOcc(operationInstanceLink);
245 grantRequest.setLinks(links);
249 protected abstract List<GrantsAddResources> getAddResources(final String vnfdId);
251 protected abstract List<GrantsAddResources> getRemoveResources(final String vnfdId);
253 protected abstract List<InlineResponse201InstantiatedVnfInfoVnfcResourceInfo> handleGrantResponse(
254 InlineResponse201 grantResponse);
256 protected abstract ChangeTypeEnum getVnfcChangeType();
258 private InlineResponse201 sendGrantRequest(final GrantRequest grantRequest) {
259 LOGGER.info("Sending grant request: {}", grantRequest);
261 final SubscriptionsAuthenticationParamsOauth2ClientCredentials subscriptionAuthentication =
262 getLastLccnSubscriptionRequest().getAuthentication().getParamsOauth2ClientCredentials();
263 final String authHeader = applicationConfig.getGrantAuth().equals("oauth")
264 ? "Bearer " + getToken(notificationClient.getApiClient(), subscriptionAuthentication)
266 final ApiResponse<InlineResponse201> response = grantClient.grantsPostWithHttpInfo(grantRequest,
267 MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, authHeader);
268 LOGGER.info("Grant Response: {}", response);
269 return response.getData();
270 } catch (final org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiException exception) {
271 LOGGER.error("Error sending notification: " + grantRequest, exception);
276 private String getVnfLink() {
277 return getLinkBaseUrl() + "/vnf_instances/" + operation.getVnfInstanceId();
280 private String getOperationLink() {
281 return getLinkBaseUrl() + "/vnf_lcm_op_occs/" + operation.getId();
284 private String getLinkBaseUrl() {
285 return applicationConfig.getBaseUrl() + "/vnflcm/v1";
288 private String getToken(final ApiClient apiClient,
289 final SubscriptionsAuthenticationParamsOauth2ClientCredentials oauthClientCredentials) {
290 final String basePath = apiClient.getBasePath().substring(0, apiClient.getBasePath().indexOf("/so/"));
291 final String tokenUrl = basePath + "/oauth/token?grant_type=client_credentials";
294 URL url = new URL(tokenUrl);
295 HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
296 connection.setRequestMethod("POST");
297 final String authorizationHeader = getAuthorizationHeader(oauthClientCredentials);
298 connection.addRequestProperty("Authorization", authorizationHeader);
300 connection.connect();
302 return getResponse(connection).get("access_token").getAsString();
303 } catch (IOException exception) {
304 LOGGER.error("Error getting token", exception);
309 private String getAuthorizationHeader(
310 final SubscriptionsAuthenticationParamsOauth2ClientCredentials oauthClientCredentials) {
311 final String auth = oauthClientCredentials.getClientId() + ":" + oauthClientCredentials.getClientPassword();
312 final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.UTF_8));
313 return "Basic " + new String(encodedAuth);
316 private JsonObject getResponse(HttpsURLConnection connection) throws IOException {
317 BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
318 String line, data = "";
319 while ((line = in.readLine()) != null) {
323 connection.getInputStream().close();
325 JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
329 private LccnSubscriptionRequest getLastLccnSubscriptionRequest() {
330 final Collection<LccnSubscriptionRequest> subscriptions = subscriptionService.getSubscriptions();
331 final Iterator<LccnSubscriptionRequest> iterator = subscriptions.iterator();
333 LccnSubscriptionRequest last = null;
335 while (iterator.hasNext()) {
336 last = iterator.next();