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