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