1 package org.onap.so.svnfm.simulator.services;
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStream;
6 import java.io.InputStreamReader;
8 import java.nio.charset.StandardCharsets;
9 import java.security.KeyStore;
10 import java.security.KeyStoreException;
11 import java.security.NoSuchAlgorithmException;
12 import java.security.UnrecoverableKeyException;
13 import java.security.cert.CertificateException;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.UUID;
19 import javax.net.ssl.HttpsURLConnection;
20 import javax.net.ssl.KeyManager;
21 import javax.net.ssl.KeyManagerFactory;
22 import javax.ws.rs.core.MediaType;
23 import org.apache.commons.codec.binary.Base64;
24 import org.modelmapper.ModelMapper;
25 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiResponse;
26 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.GrantRequest;
27 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.GrantsAddResources;
28 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.GrantsLinks;
29 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.GrantsLinksVnfLcmOpOcc;
30 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.InlineResponse201;
31 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.ApiClient;
32 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.ApiException;
33 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.api.DefaultApi;
34 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs;
35 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.ChangeTypeEnum;
36 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinks;
37 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance;
38 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification;
39 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.NotificationStatusEnum;
40 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.NotificationTypeEnum;
41 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationEnum;
42 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum;
43 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
44 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201InstantiatedVnfInfoVnfcResourceInfo;
45 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.LccnSubscriptionRequest;
46 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsAuthenticationParamsBasic;
47 import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsAuthenticationParamsOauth2ClientCredentials;
48 import org.onap.so.svnfm.simulator.api.VeVnfmApi;
49 import org.onap.so.svnfm.simulator.config.ApplicationConfig;
50 import org.onap.so.svnfm.simulator.model.VnfOperation;
51 import org.onap.so.svnfm.simulator.model.Vnfds;
52 import org.onap.so.svnfm.simulator.repository.VnfOperationRepository;
53 import org.onap.so.svnfm.simulator.util.PatternContainedChecker;
54 import org.slf4j.Logger;
55 import org.slf4j.LoggerFactory;
56 import org.springframework.core.io.ClassPathResource;
57 import org.springframework.core.io.Resource;
58 import com.google.gson.JsonObject;
59 import com.google.gson.JsonParser;
61 public abstract class OperationProgressor implements Runnable {
63 private static final Logger LOGGER = LoggerFactory.getLogger(OperationProgressor.class);
64 private static final String CERTIFICATE_TO_TRUST = "so-vnfm-adapter.crt.pem";
65 protected final VnfOperation operation;
66 protected final SvnfmService svnfmService;
67 protected final Vnfds vnfds;
68 private final VnfOperationRepository vnfOperationRepository;
69 private final ApplicationConfig applicationConfig;
70 private final SubscriptionService subscriptionService;
71 private final DefaultApi notificationClient;
72 private final org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.api.DefaultApi grantClient;
73 private final Resource keyStoreResource = new ClassPathResource("so-vnfm-simulator.p12");
74 private final String keyStorePassword = "7Em3&j4.19xYiMelhD5?xbQ.";
76 public OperationProgressor(final VnfOperation operation, final SvnfmService svnfmService,
77 final VnfOperationRepository vnfOperationRepository, final ApplicationConfig applicationConfig,
78 final Vnfds vnfds, final SubscriptionService subscriptionService) {
79 this.operation = operation;
80 this.svnfmService = svnfmService;
81 this.vnfOperationRepository = vnfOperationRepository;
82 this.applicationConfig = applicationConfig;
84 this.subscriptionService = subscriptionService;
86 final ApiClient apiClient = new ApiClient();
87 String callBackUrl = getLastLccnSubscriptionRequest().getCallbackUri();
88 final PatternContainedChecker checker = new PatternContainedChecker("/lcn/", callBackUrl);
89 callBackUrl = checker.getText();
90 apiClient.setBasePath(callBackUrl);
91 apiClient.setKeyManagers(getKeyManagers());
92 apiClient.setSslCaCert(getCertificateToTrust());
93 notificationClient = checker.isContained() ? new DefaultApi(apiClient) : new VeVnfmApi(apiClient);
95 final org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiClient grantApiClient =
96 new org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiClient();
97 grantApiClient.setBasePath(callBackUrl);
98 grantApiClient.setKeyManagers(getKeyManagers());
99 grantApiClient.setSslCaCert(getCertificateToTrust());
100 grantClient = new org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.api.DefaultApi(grantApiClient);
103 private InputStream getCertificateToTrust() {
105 return new ClassPathResource(CERTIFICATE_TO_TRUST).getInputStream();
106 } catch (final IOException exception) {
107 LOGGER.error("Error reading certificate to trust, https calls to VNFM adapter will fail", exception);
112 private KeyManager[] getKeyManagers() {
115 keystore = KeyStore.getInstance("pkcs12");
116 keystore.load(keyStoreResource.getInputStream(), keyStorePassword.toCharArray());
117 KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
118 keyManagerFactory.init(keystore, keyStorePassword.toCharArray());
119 return keyManagerFactory.getKeyManagers();
120 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException
121 | UnrecoverableKeyException exception) {
122 LOGGER.error("Error reading certificate, https calls using two way TLS to VNFM adapter will fail",
124 return new KeyManager[0];
131 final VnfLcmOperationOccurrenceNotification notificationOfStarting =
132 buildNotification(NotificationStatusEnum.START, OperationStateEnum.STARTING);
133 sendNotification(notificationOfStarting);
136 setState(InlineResponse200.OperationStateEnum.PROCESSING);
137 final VnfLcmOperationOccurrenceNotification notificationOfProcessing =
138 buildNotification(NotificationStatusEnum.START, OperationStateEnum.PROCESSING);
139 sendNotification(notificationOfProcessing);
141 final GrantRequest grantRequest = buildGrantRequest();
142 final InlineResponse201 grantResponse = sendGrantRequest(grantRequest);
143 final List<InlineResponse201InstantiatedVnfInfoVnfcResourceInfo> vnfcs = handleGrantResponse(grantResponse);
145 svnfmService.getVnf(operation.getVnfInstanceId()).getInstantiatedVnfInfo();
148 setState(InlineResponse200.OperationStateEnum.COMPLETED);
149 final VnfLcmOperationOccurrenceNotification notificationOfCompleted =
150 buildNotification(NotificationStatusEnum.RESULT, OperationStateEnum.COMPLETED);
151 notificationOfCompleted.setAffectedVnfcs(getVnfcs(vnfcs));
153 sendNotification(notificationOfCompleted);
154 } catch (final Exception exception) {
155 LOGGER.error("Error in OperationProgressor ", exception);
159 private void sleep(final long milliSeconds) {
161 Thread.sleep(milliSeconds);
162 } catch (final InterruptedException e) {
163 operation.setOperationState(InlineResponse200.OperationStateEnum.FAILED);
164 // Restore interrupted state
165 Thread.currentThread().interrupt();
169 private void setState(final InlineResponse200.OperationStateEnum state) {
170 LOGGER.info("Setting state to {} for operation {}", state, operation.getId());
171 operation.setOperationState(state);
172 vnfOperationRepository.save(operation);
175 private VnfLcmOperationOccurrenceNotification buildNotification(final NotificationStatusEnum status,
176 final OperationStateEnum operationState) {
177 final VnfLcmOperationOccurrenceNotification notification = new VnfLcmOperationOccurrenceNotification();
178 notification.setId(UUID.randomUUID().toString());
179 notification.setNotificationType(NotificationTypeEnum.VNFLCMOPERATIONOCCURRENCENOTIFICATION);
180 notification.setNotificationStatus(status);
181 notification.setOperationState(operationState);
182 notification.setOperation(OperationEnum.fromValue(operation.getOperation().toString()));
183 notification.setVnfInstanceId(operation.getVnfInstanceId());
184 notification.setVnfLcmOpOccId(operation.getId());
186 final LcnVnfLcmOperationOccurrenceNotificationLinks links = new LcnVnfLcmOperationOccurrenceNotificationLinks();
187 final LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance vnfInstanceLink =
188 new LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance();
189 vnfInstanceLink.setHref(getVnfLink());
190 links.setVnfInstance(vnfInstanceLink);
192 final LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance operationLink =
193 new LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance();
194 operationLink.setHref(getOperationLink());
195 links.setVnfLcmOpOcc(operationLink);
197 notification.setLinks(links);
202 private List<LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs> getVnfcs(
203 final List<InlineResponse201InstantiatedVnfInfoVnfcResourceInfo> instantiatedVnfcs) {
204 final List<LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs> vnfcs = new ArrayList<>();
205 if (instantiatedVnfcs != null) {
206 for (final InlineResponse201InstantiatedVnfInfoVnfcResourceInfo instantiatedVnfc : instantiatedVnfcs) {
207 LOGGER.info("VNFC TO BE CONVERTED: {}", instantiatedVnfc);
208 final ModelMapper mapper = new ModelMapper();
209 final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc =
210 mapper.map(instantiatedVnfc, LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.class);
211 LOGGER.info("VNFC FROM CONVERSION: {}", vnfc);
212 vnfc.setChangeType(getVnfcChangeType());
219 private void sendNotification(final VnfLcmOperationOccurrenceNotification notification) {
220 LOGGER.info("Sending notification: {}", notification);
222 final SubscriptionsAuthenticationParamsBasic subscriptionAuthentication =
223 getLastLccnSubscriptionRequest().getAuthentication().getParamsBasic();
225 subscriptionAuthentication.getUserName() + ":" + subscriptionAuthentication.getPassword();
226 final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
227 String authHeader = "Basic " + new String(encodedAuth);
228 notificationClient.lcnVnfLcmOperationOccurrenceNotificationPostWithHttpInfo(notification,
229 MediaType.APPLICATION_JSON, authHeader);
230 } catch (final ApiException exception) {
231 LOGGER.error("Error sending notification: " + notification, exception);
232 LOGGER.error("Response code: {}, body: {}, basePath: {}", exception.getCode(), exception.getResponseBody(),
233 notificationClient.getApiClient().getBasePath());
237 public GrantRequest buildGrantRequest() {
238 final GrantRequest grantRequest = new GrantRequest();
239 grantRequest.setVnfInstanceId(operation.getVnfInstanceId());
240 final String vnfdId = svnfmService.getVnf(operation.getVnfInstanceId()).getVnfdId();
241 grantRequest.setVnfdId(vnfdId);
242 grantRequest.setAddResources(getAddResources(vnfdId));
243 grantRequest.setRemoveResources(getRemoveResources(vnfdId));
244 grantRequest.setVnfLcmOpOccId(operation.getId());
246 .setOperation(org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.model.GrantRequest.OperationEnum
247 .fromValue(operation.getOperation().getValue()));
248 grantRequest.setIsAutomaticInvocation(false);
250 final GrantsLinksVnfLcmOpOcc vnfInstanceLink = new GrantsLinksVnfLcmOpOcc();
251 vnfInstanceLink.setHref(getVnfLink());
252 final GrantsLinksVnfLcmOpOcc operationInstanceLink = new GrantsLinksVnfLcmOpOcc();
253 operationInstanceLink.setHref(getOperationLink());
254 final GrantsLinks links = new GrantsLinks();
255 links.setVnfInstance(vnfInstanceLink);
256 links.setVnfLcmOpOcc(operationInstanceLink);
257 grantRequest.setLinks(links);
261 protected abstract List<GrantsAddResources> getAddResources(final String vnfdId);
263 protected abstract List<GrantsAddResources> getRemoveResources(final String vnfdId);
265 protected abstract List<InlineResponse201InstantiatedVnfInfoVnfcResourceInfo> handleGrantResponse(
266 InlineResponse201 grantResponse);
268 protected abstract ChangeTypeEnum getVnfcChangeType();
270 private InlineResponse201 sendGrantRequest(final GrantRequest grantRequest) {
271 LOGGER.info("Sending grant request: {}", grantRequest);
273 final SubscriptionsAuthenticationParamsOauth2ClientCredentials subscriptionAuthentication =
274 getLastLccnSubscriptionRequest().getAuthentication().getParamsOauth2ClientCredentials();
275 SubscriptionsAuthenticationParamsBasic paramsBasic =
276 getLastLccnSubscriptionRequest().getAuthentication().getParamsBasic();
278 final String authHeader = applicationConfig.getGrantAuth().equals("oauth")
279 ? "Bearer " + getToken(notificationClient.getApiClient(), subscriptionAuthentication)
280 : getAuthorizationHeader(paramsBasic.getUserName(), paramsBasic.getPassword());
282 LOGGER.info("Sending grant request with authorization: {}", authHeader);
283 final ApiResponse<InlineResponse201> response = grantClient.grantsPostWithHttpInfo(grantRequest,
284 MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, authHeader);
285 LOGGER.info("Grant Response: {}", response);
286 return response.getData();
287 } catch (final org.onap.so.adapters.vnfmadapter.extclients.vnfm.grant.ApiException exception) {
288 LOGGER.error("Status: {}", exception.getCode());
289 LOGGER.error("ResponseHeaders: {}", exception.getResponseHeaders());
290 LOGGER.error("ResponseBody: {}", exception.getResponseBody());
291 LOGGER.error("Error sending notification: " + grantRequest, exception);
296 private String getVnfLink() {
297 return getLinkBaseUrl() + "/vnf_instances/" + operation.getVnfInstanceId();
300 private String getOperationLink() {
301 return getLinkBaseUrl() + "/vnf_lcm_op_occs/" + operation.getId();
304 private String getLinkBaseUrl() {
305 return applicationConfig.getBaseUrl() + "/vnflcm/v1";
308 private String getToken(final ApiClient apiClient,
309 final SubscriptionsAuthenticationParamsOauth2ClientCredentials oauthClientCredentials) {
310 final String basePath = apiClient.getBasePath().substring(0, apiClient.getBasePath().indexOf("/so/"));
311 final String tokenUrl = basePath + "/oauth/token?grant_type=client_credentials";
314 URL url = new URL(tokenUrl);
315 HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
316 connection.setRequestMethod("POST");
317 final String authorizationHeader = getAuthorizationHeader(oauthClientCredentials);
318 connection.addRequestProperty("Authorization", authorizationHeader);
320 connection.connect();
322 return getResponse(connection).get("access_token").getAsString();
323 } catch (IOException exception) {
324 LOGGER.error("Error getting token", exception);
329 private String getAuthorizationHeader(
330 final SubscriptionsAuthenticationParamsOauth2ClientCredentials oauthClientCredentials) {
331 return getAuthorizationHeader(oauthClientCredentials.getClientId(), oauthClientCredentials.getClientPassword());
334 private String getAuthorizationHeader(final String username, final String password) {
335 final String auth = username + ":" + password;
336 final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.UTF_8));
337 return "Basic " + new String(encodedAuth);
340 private JsonObject getResponse(HttpsURLConnection connection) throws IOException {
341 BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
342 String line, data = "";
343 while ((line = in.readLine()) != null) {
347 connection.getInputStream().close();
349 JsonObject jsonObject = new JsonParser().parse(data).getAsJsonObject();
353 private LccnSubscriptionRequest getLastLccnSubscriptionRequest() {
354 final Collection<LccnSubscriptionRequest> subscriptions = subscriptionService.getSubscriptions();
355 final Iterator<LccnSubscriptionRequest> iterator = subscriptions.iterator();
357 LccnSubscriptionRequest last = null;
359 while (iterator.hasNext()) {
360 last = iterator.next();