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