d17a3c42a64d8b520cc29a222281de04dd2548fd
[so.git] / bpmn / MSOCommonBPMN / src / main / groovy / org / onap / so / bpmn / common / scripts / OofHoming.groovy
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2018 Intel Corp. All rights reserved.
6  * ================================================================================
7  * Modifications Copyright (c) 2019 Samsung
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22 package org.onap.so.bpmn.common.scripts
23
24 import org.onap.so.bpmn.core.UrnPropertiesReader
25 import org.camunda.bpm.engine.delegate.BpmnError
26 import org.camunda.bpm.engine.delegate.DelegateExecution
27
28 import org.onap.so.bpmn.core.domain.InventoryType
29 import org.onap.so.bpmn.core.domain.Resource
30 import org.onap.so.bpmn.core.domain.ResourceType
31 import org.onap.so.bpmn.core.domain.ServiceDecomposition
32 import org.onap.so.bpmn.core.domain.Subscriber
33 import org.onap.so.bpmn.core.domain.VnfResource
34 import org.onap.so.bpmn.core.json.JsonUtils
35 import org.onap.so.client.HttpClient
36 import org.onap.so.client.HttpClientFactory
37 import org.slf4j.Logger
38 import org.slf4j.LoggerFactory
39 import org.onap.so.db.catalog.beans.CloudIdentity
40 import org.onap.so.db.catalog.beans.CloudSite
41 import org.onap.so.db.catalog.beans.HomingInstance
42 import org.onap.so.bpmn.common.scripts.AbstractServiceTaskProcessor
43 import org.onap.so.utils.TargetEntity
44
45 import org.json.JSONArray
46 import org.json.JSONObject
47 import org.springframework.web.util.UriUtils
48
49 import static org.onap.so.bpmn.common.scripts.GenericUtils.*
50
51 import javax.ws.rs.core.Response
52
53 /**
54  * This class contains the scripts used
55  * by the OOF Homing Subflow building block. The
56  * subflow attempts to home the provided
57  * resources by calling OOF.
58  */
59 class OofHoming extends AbstractServiceTaskProcessor {
60     private static final Logger logger = LoggerFactory.getLogger( OofHoming.class);
61
62     ExceptionUtil exceptionUtil = new ExceptionUtil()
63     JsonUtils jsonUtil = new JsonUtils()
64     OofUtils oofUtils = new OofUtils(this)
65
66     /**
67      * This method validates the incoming variables.
68      * The method then prepares the OOF request
69      * and posts it to OOF's rest api.
70      *
71      * @param execution
72      */
73     public void callOof(DelegateExecution execution) {
74         execution.setVariable("prefix", "HOME_")
75         logger.debug( "*** Started Homing Call OOF ***")
76         try {
77             execution.setVariable("rollbackData", null)
78             execution.setVariable("rolledBack", false)
79
80             String requestId = execution.getVariable("msoRequestId")
81             logger.debug( "Incoming Request Id is: " + requestId)
82             String serviceInstanceId = execution.getVariable("serviceInstanceId")
83             logger.debug( "Incoming Service Instance Id is: " + serviceInstanceId)
84             String serviceInstanceName = execution.getVariable("serviceInstanceName")
85             logger.debug( "Incoming Service Instance Name is: " + serviceInstanceName)
86             ServiceDecomposition serviceDecomposition = execution.getVariable("serviceDecomposition")
87             logger.debug( "Incoming Service Decomposition is: " + serviceDecomposition)
88             String subscriberInfo = execution.getVariable("subscriberInfo")
89             logger.debug( "Incoming Subscriber Information is: " + subscriberInfo)
90             Map customerLocation = execution.getVariable("customerLocation")
91             logger.debug( "Incoming Customer Location is: " + customerLocation.toString())
92             String cloudOwner = execution.getVariable("cloudOwner")
93             logger.debug( "Incoming cloudOwner is: " + cloudOwner)
94             String cloudRegionId = execution.getVariable("cloudRegionId")
95             logger.debug( "Incoming cloudRegionId is: " + cloudRegionId)
96
97             if (isBlank(requestId) ||
98                     isBlank(serviceInstanceId) ||
99                     isBlank(serviceInstanceName) ||
100                     isBlank(serviceDecomposition.toString()) ||
101                     isBlank(customerLocation.toString())) {
102                 exceptionUtil.buildAndThrowWorkflowException(execution, 4000,
103                         "A required input variable is missing or null")
104             } else {
105                 Subscriber subscriber = null
106                 if (isBlank(subscriberInfo)) {
107                     subscriber = new Subscriber("", "", "")
108                 } else {
109                 String subId = jsonUtil.getJsonValue(subscriberInfo, "globalSubscriberId")
110                 String subName = jsonUtil.getJsonValue(subscriberInfo, "subscriberName")
111                 String subCommonSiteId = ""
112                 if (jsonUtil.jsonElementExist(subscriberInfo, "subscriberCommonSiteId")) {
113                     subCommonSiteId = jsonUtil.getJsonValue(subscriberInfo, "subscriberCommonSiteId")
114                 }
115                     subscriber = new Subscriber(subId, subName, subCommonSiteId)
116                 }
117
118                 //Authentication
119                 def authHeader = ""
120                 String basicAuth = UrnPropertiesReader.getVariable("mso.oof.auth", execution)
121                 String msokey = UrnPropertiesReader.getVariable("mso.msoKey", execution)
122
123                 String basicAuthValue = utils.encrypt(basicAuth, msokey)
124                 if (basicAuthValue != null) {
125                     logger.debug( "Obtained BasicAuth username and password for OOF Adapter: " + basicAuthValue)
126                     try {
127                         authHeader = utils.getBasicAuth(basicAuthValue, msokey)
128                         execution.setVariable("BasicAuthHeaderValue", authHeader)
129                     } catch (Exception ex) {
130                         logger.debug( "Unable to encode username and password string: " + ex)
131                         exceptionUtil.buildAndThrowWorkflowException(execution, 401, "Internal Error - Unable to " +
132                                 "encode username and password string")
133                     }
134                 } else {
135                     logger.debug( "Unable to obtain BasicAuth - BasicAuth value null")
136                     exceptionUtil.buildAndThrowWorkflowException(execution, 401, "Internal Error - BasicAuth " +
137                             "value null")
138                 }
139
140                 //Prepare Callback
141                 String timeout = execution.getVariable("timeout")
142                 if (isBlank(timeout)) {
143                     timeout = UrnPropertiesReader.getVariable("mso.oof.timeout", execution);
144                     if (isBlank(timeout)) {
145                         timeout = "PT30M"
146                     }
147                 }
148                 logger.debug( "Async Callback Timeout will be: " + timeout)
149
150                 execution.setVariable("timeout", timeout)
151                 execution.setVariable("correlator", requestId)
152                 execution.setVariable("messageType", "oofResponse")
153
154                 //Build Request & Call OOF
155                 String oofRequest = oofUtils.buildRequest(execution, requestId, serviceDecomposition,
156                         subscriber, customerLocation)
157                 execution.setVariable("oofRequest", oofRequest)
158                 logger.debug( "OOF Request is: " + oofRequest)
159
160                 String urlString = UrnPropertiesReader.getVariable("mso.oof.endpoint", execution)
161                 logger.debug( "Posting to OOF Url: " + urlString)
162
163
164                                 URL url = new URL(urlString);
165                 HttpClient httpClient = new HttpClientFactory().newJsonClient(url, TargetEntity.SNIRO)
166                 httpClient.addAdditionalHeader("Authorization", authHeader)
167                                 Response httpResponse = httpClient.post(oofRequest)
168
169                                 int responseCode = httpResponse.getStatus()
170                                 logger.debug("OOF sync response code is: " + responseCode)
171
172
173                 logger.debug( "*** Completed Homing Call OOF ***")
174             }
175         } catch (BpmnError b) {
176             throw b
177         } catch (Exception e) {
178                         logger.error(e);
179             exceptionUtil.buildAndThrowWorkflowException(execution, 2500,
180                     "Internal Error - Occured in Homing callOof: " + e.getMessage())
181         }
182     }
183
184     /**
185      * This method processes the callback response
186      * and the contained homing solution. It sets
187      * homing solution assignment and license
188      * information to the corresponding resources
189      *
190      * @param execution
191      */
192     public void processHomingSolution(DelegateExecution execution) {
193
194         logger.debug( "*** Started Homing Process Homing Solution ***")
195         try {
196             String response = execution.getVariable("asyncCallbackResponse")
197             logger.debug( "OOF Async Callback Response is: " + response)
198
199             oofUtils.validateCallbackResponse(execution, response)
200             String placements = jsonUtil.getJsonValue(response, "solutions.placementSolutions")
201             logger.debug( "****** Solution Placements: " + placements + " *****")
202
203             ServiceDecomposition decomposition = execution.getVariable("serviceDecomposition")
204             logger.debug( "Service Decomposition: " + decomposition)
205
206             List<Resource> resourceList = decomposition.getServiceResources()
207             JSONArray arr = new JSONArray(placements)
208             for (int i = 0; i < arr.length(); i++) {
209                 JSONArray arrSol = arr.getJSONArray(i)
210                 for (int j = 0; j < arrSol.length(); j++) {
211                     JSONObject placement = arrSol.getJSONObject(j)
212                     logger.debug( "****** Placement Solution is: " + placement + " *****")
213                     String jsonServiceResourceId = jsonUtil.getJsonValue( placement.toString(), "serviceResourceId")
214                     logger.debug( "****** homing serviceResourceId is: " + jsonServiceResourceId + " *****")
215                     for (Resource resource : resourceList) {
216                         String serviceResourceId = resource.getResourceId()
217                         logger.debug( "****** decomp serviceResourceId is: " + serviceResourceId + " *****")
218                         if (serviceResourceId.equalsIgnoreCase(jsonServiceResourceId)) {
219                             JSONObject solution = placement.getJSONObject("solution")
220                             String solutionType = solution.getString("identifierType")
221                             String inventoryType = ""
222                             if (solutionType.equalsIgnoreCase("serviceInstanceId")) {
223                                 inventoryType = "service"
224                             } else {
225                                 inventoryType = "cloud"
226                             }
227                             logger.debug( "****** homing inventoryType is: " + inventoryType + " *****")
228                             resource.getHomingSolution().setInventoryType(InventoryType.valueOf(inventoryType))
229
230                             JSONArray assignmentArr = placement.getJSONArray("assignmentInfo")
231                             logger.debug( "****** assignmentInfo is: " + assignmentArr.toString() + " *****")
232
233                             Map<String, String> assignmentMap = jsonUtil.entryArrayToMap(execution,
234                                     assignmentArr.toString(), "key", "value")
235                             String oofDirectives = null
236                             assignmentMap.each { key, value ->
237                                 logger.debug( "****** element: " + key + " *****")
238                                 if (key == "oof_directives") {
239                                     oofDirectives = value
240                                     logger.debug( "****** homing oofDirectives: " + oofDirectives + " *****")
241                                 }
242                             }
243                             String cloudOwner = assignmentMap.get("cloudOwner")
244                             logger.debug( "****** homing cloudOwner: " + cloudOwner + " *****")
245                             String cloudRegionId = assignmentMap.get("locationId")
246                             logger.debug( "****** homing cloudRegionId: " + cloudRegionId + " *****")
247                             resource.getHomingSolution().setCloudOwner(cloudOwner)
248                             resource.getHomingSolution().setCloudRegionId(cloudRegionId)
249
250                             CloudSite cloudSite = new CloudSite()
251                             cloudSite.setId(cloudRegionId)
252                             cloudSite.setRegionId(cloudRegionId)
253                             String orchestrator = execution.getVariable("orchestrator")
254                             if ((orchestrator != null) && (orchestrator != "")) {
255                                 cloudSite.setOrchestrator(orchestrator)
256                                 logger.debug( "****** orchestrator: " + orchestrator + " *****")
257                             } else {
258                                 cloudSite.setOrchestrator("multicloud")
259                             }
260
261                             CloudIdentity cloudIdentity = new CloudIdentity()
262                             cloudIdentity.setId(cloudRegionId)
263                             cloudIdentity.setIdentityServerType(ServerType."KEYSTONE")
264                             cloudIdentity.setAdminTenant("service")
265                             cloudIdentity.setIdentityAuthenticationType(AuthenticationType.USERNAME_PASSWORD)
266                             String msoMulticloudUserName = UrnPropertiesReader
267                                     .getVariable("mso.multicloud.api.username", execution,
268                                     "apih")
269                             String msoMulticloudPassword = UrnPropertiesReader
270                                     .getVariable("mso.multicloud.api.password", execution,
271                                     "abc123")
272                             cloudIdentity.setMsoId(msoMulticloudUserName)
273                             cloudIdentity.setMsoPass(msoMulticloudPassword)
274                             // Get MSB Url
275                             String msbHost = oofUtils.getMsbHost(execution)
276                             String multicloudApiEndpoint = UrnPropertiesReader
277                                     .getVariable("mso.multicloud.api.endpoint", execution,
278                                     "/api/multicloud-titaniumcloud/v1")
279                             cloudIdentity.setIdentityUrl(msbHost + multicloudApiEndpoint
280                                     + "/" + cloudOwner + "/" +
281                                     cloudRegionId + "/infra_workload")
282                             logger.debug( "****** Cloud IdentityUrl: " + msbHost + multicloudApiEndpoint
283                                     + "/" + cloudOwner + "/" +
284                                     cloudRegionId + "/infra_workload"
285                                     + " *****")
286                             logger.debug( "****** CloudIdentity: " + cloudIdentity.toString()
287                                     + " *****")
288                             cloudSite.setIdentityService(cloudIdentity)
289                             logger.debug( "****** CloudSite: " + cloudSite.toString()
290                                     + " *****")
291
292                             // Set cloudsite in catalog DB here
293                             oofUtils.createCloudSite(cloudSite, execution)
294
295                             if (oofDirectives != null && oofDirectives != "") {
296                                 resource.getHomingSolution().setOofDirectives(oofDirectives)
297                                 execution.setVariable("oofDirectives", oofDirectives)
298                                 logger.debug( "***** OofDirectives set to: " + oofDirectives +
299                                         " *****", "true")
300                             }
301
302                             // Set Homing Instance
303                             String serviceInstanceId = decomposition.getServiceInstance().getInstanceId()
304                             HomingInstance homingInstance = new HomingInstance()
305                             homingInstance.setServiceInstanceId(serviceInstanceId)
306                             homingInstance.setCloudOwner(cloudOwner)
307                             homingInstance.setCloudRegionId(cloudRegionId)
308                             if (oofDirectives != null && oofDirectives != "") {
309                                 homingInstance.setOofDirectives(oofDirectives)}
310                             else {
311                                 homingInstance.setOofDirectives("{}")
312                             }
313                             oofUtils.createHomingInstance(homingInstance, execution)
314
315                             if (inventoryType.equalsIgnoreCase("service")) {
316                                 resource.getHomingSolution().setRehome(assignmentMap.get("isRehome").toBoolean())
317                                 VnfResource vnf = new VnfResource()
318                                 vnf.setVnfHostname(assignmentMap.get("vnfHostName"))
319                                 resource.getHomingSolution().setVnf(vnf)
320                                 resource.getHomingSolution().setServiceInstanceId(solution.getJSONArray("identifiers")[0].toString())
321                             }
322                         } else {
323                             logger.debug( "ProcessHomingSolution Exception: no matching serviceResourceIds returned in " +
324                                     "homing solution")
325                             exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - " +
326                                     "Occurred in Homing ProcessHomingSolution: no matching serviceResourceIds returned")
327
328                         }
329                     }
330                 }
331                 if (JsonUtils.jsonElementExist(response, "solutions.licenseSolutions")) {
332                     String licenseSolutions = jsonUtil.getJsonValue(response, "solutions.licenseSolutions")
333                     JSONArray licenseArr = new JSONArray(licenseSolutions)
334                     for (int l = 0; l < licenseArr.length(); l++) {
335                         JSONObject license = licenseArr.getJSONObject(l)
336                         String jsonServiceResourceId = license.getString("serviceResourceId")
337                         for (Resource resource : resourceList) {
338                             String serviceResourceId = resource.getResourceId()
339                             if (serviceResourceId.equalsIgnoreCase(jsonServiceResourceId)) {
340                                 String jsonEntitlementPoolList = jsonUtil.getJsonValue(license.toString(), "entitlementPoolUUID")
341                                 List<String> entitlementPoolList = jsonUtil.StringArrayToList(execution, jsonEntitlementPoolList)
342                                 resource.getHomingSolution().getLicense().setEntitlementPoolList(entitlementPoolList)
343
344                                 String jsonLicenseKeyGroupList = jsonUtil.getJsonValue(license.toString(), "licenseKeyGroupUUID")
345                                 List<String> licenseKeyGroupList = jsonUtil.StringArrayToList(execution, jsonLicenseKeyGroupList)
346                                 resource.getHomingSolution().getLicense().setLicenseKeyGroupList(licenseKeyGroupList)
347                             }
348                         }
349                     }
350                 }
351             }
352             execution.setVariable("serviceDecomposition", decomposition)
353             execution.setVariable("homingSolution", placements) //TODO - can be removed as output variable
354
355             logger.debug( "*** Completed Homing Process Homing Solution ***")
356         } catch (BpmnError b) {
357             logger.debug( "ProcessHomingSolution Error: " + b)
358             throw b
359         } catch (Exception e) {
360             logger.debug( "ProcessHomingSolution Exception: " + e)
361                         logger.error(e);
362             exceptionUtil.buildAndThrowWorkflowException(execution, 2500, "Internal Error - Occurred in Homing ProcessHomingSolution")
363         }
364     }
365
366     /**
367      * This method logs the start of DHVCreateService
368      * to make debugging easier.
369      *
370      * @param - execution
371      */
372     public String logStart(DelegateExecution execution) {
373
374         String requestId = execution.getVariable("testReqId")
375         if (isBlank(requestId)) {
376             requestId = execution.getVariable("msoRequestId")
377         }
378         execution.setVariable("DHVCS_requestId", requestId)
379         logger.debug( "***** STARTED Homing Subflow for request: " + requestId + " *****")
380     }
381
382     /**
383      * Auto-generated method stub
384      */
385     public void preProcessRequest(DelegateExecution execution) {}
386         // Not Implemented Method
387
388     /**
389      * Constructs a workflow message callback URL for the specified message type and correlator.
390      * This type of callback URL is used when a workflow wants an MSO adapter (like the SDNC
391      * adapter) to call it back.  In other words, this is for callbacks internal to the MSO
392      * complex.  Use <code>createWorkflowMessageAdapterCallbackURL</code> if the callback
393      * will come from outside the MSO complex.
394      * @param endpoint endpoint address to contruct URL from
395      * @param messageType the message type (e.g. SDNCAResponse or VNFAResponse)
396      * @param correlator the correlator value (e.g. a request ID)
397      */
398     public String createHomingCallbackURL(String endpoint, String messageType, String correlator) {
399         try {
400             if (endpoint == null || endpoint.isEmpty()) {
401                 ExceptionUtil exceptionUtil = new ExceptionUtil()
402                 exceptionUtil.buildAndThrowWorkflowException(execution, 2000,
403                         'mso:workflow:message:endpoint was not passed in')
404             }
405
406             logger.debug( "passed in endpoint: " + endpoint + " *****")
407
408             while (endpoint.endsWith('/')) {
409                 endpoint = endpoint.substring(0, endpoint.length() - 1)
410             }
411             logger.debug( "processed endpoint: " + endpoint + " *****")
412
413             return endpoint +
414                     '/' + UriUtils.encodePathSegment(messageType, 'UTF-8') +
415                     '/' + UriUtils.encodePathSegment(correlator, 'UTF-8')
416         } catch (Exception ex) {
417             logger.debug( "createCallbackURL Exception: " + ex + " *****")
418         }
419     }
420 }