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