Fix issues in NSMF terminate flow
[so.git] / bpmn / so-bpmn-infrastructure-common / src / main / groovy / org / onap / so / bpmn / infrastructure / scripts / DoDeleteSliceService.groovy
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  # Copyright (c) 2019, CMCC Technologies Co., Ltd.
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.infrastructure.scripts
21
22 import org.camunda.bpm.engine.delegate.BpmnError
23 import org.camunda.bpm.engine.delegate.DelegateExecution
24 import org.onap.aai.domain.yang.AllottedResource
25 import org.onap.aai.domain.yang.AllottedResources
26 import org.onap.aai.domain.yang.Relationship
27 import org.onap.aai.domain.yang.ServiceInstance
28 import org.onap.aaiclient.client.aai.AAIObjectName
29 import org.onap.aaiclient.client.aai.entities.AAIResultWrapper
30 import org.onap.aaiclient.client.aai.entities.uri.AAIResourceUri
31 import org.onap.aaiclient.client.aai.entities.uri.AAIUriFactory
32 import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder
33 import org.onap.aaiclient.client.generated.fluentbuilders.AAIFluentTypeBuilder.Types
34 import org.onap.so.client.oof.adapter.beans.payload.OofRequest
35 import org.onap.logging.filter.base.ONAPComponents
36 import org.onap.so.bpmn.common.scripts.AbstractServiceTaskProcessor
37 import org.onap.so.bpmn.common.scripts.ExceptionUtil
38 import org.onap.so.bpmn.common.scripts.OofUtils
39 import org.onap.so.bpmn.core.UrnPropertiesReader
40 import org.onap.so.client.HttpClient
41 import org.onap.so.client.HttpClientFactory
42 import org.slf4j.Logger
43 import org.slf4j.LoggerFactory
44 import com.fasterxml.jackson.databind.ObjectMapper
45
46 import javax.ws.rs.NotFoundException
47 import javax.ws.rs.core.Response
48
49 import static org.apache.commons.lang3.StringUtils.isBlank
50
51 /**
52  * This groovy class supports the <class>DoDeleteSliceService.bpmn</class> process.
53  *
54  * Inputs:
55  * @param - msoRequestId
56  * @param - globalSubscriberId - O
57  * @param - subscriptionServiceType - O
58  * @param - serviceInstanceId
59  *
60  */
61 class DoDeleteSliceService extends AbstractServiceTaskProcessor {
62     private final String PREFIX ="DoDeleteSliceService"
63     ExceptionUtil exceptionUtil = new ExceptionUtil()
64     OofUtils oofUtils = new OofUtils()
65     private static final Logger LOGGER = LoggerFactory.getLogger( DoDeleteSliceService.class)
66
67     @Override
68     void preProcessRequest(DelegateExecution execution) {
69         LOGGER.debug(" *****${PREFIX} preProcessRequest *****")
70         String msg = ""
71
72         try {
73             //String requestId = execution.getVariable("msoRequestId")
74             execution.setVariable("prefix",PREFIX)
75
76             //Inputs
77             //requestDetails.subscriberInfo. for AAI GET & PUT
78              execution.getVariable("globalSubscriberId") ?: execution.setVariable("globalSubscriberId", "")
79
80             //requestDetails.requestParameters. for AAI PUT
81             execution.getVariable("serviceType") ?: execution.setVariable("serviceType", "")
82
83             //Generated in parent for AAI PUT
84             String serviceInstanceId = execution.getVariable("serviceInstanceId")
85             if (isBlank(serviceInstanceId)){
86                 msg = "Input serviceInstanceId is null"
87                 LOGGER.info(msg)
88                 exceptionUtil.buildAndThrowWorkflowException(execution, 500, msg)
89             }
90         } catch (BpmnError e) {
91             throw e
92         } catch (Exception ex){
93             msg = "Exception in preProcessRequest " + ex.getMessage()
94             LOGGER.error(msg)
95             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg)
96         }
97         LOGGER.debug("*****${PREFIX} Exit preProcessRequest *****")
98     }
99
100     /**
101      * query E2ESliceService from AAI
102      * save snssai
103      * @param execution
104      */
105     void queryServiceProfileFromAAI(DelegateExecution execution)
106     {
107         LOGGER.trace(" *****${PREFIX} Start queryE2ESliceSeriveFromAAI *****")
108         String serviceInstanceId = execution.getVariable("serviceInstanceId")
109         try
110         {
111         String errorMsg = "query e2e slice service from aai failed"
112         AAIResultWrapper wrapper = queryAAI(execution, Types.SERVICE_INSTANCE, serviceInstanceId, errorMsg)
113         Optional<ServiceInstance> si =wrapper.asBean(ServiceInstance.class)
114         if(si.isPresent())
115         {
116             String snssai = si.get()?.getEnvironmentContext()
117             execution.setVariable("snssai", snssai ?: "")
118 //            ServiceProfiles serviceProfiles = si.get()?.getServiceProfiles()
119 //            ServiceProfile serviceProfile = serviceProfiles.getServiceProfile().get(0)
120 //            String serviceProfileId = serviceProfile ? serviceProfile.getProfileId() : ""
121 //            execution.setVariable("serviceProfileId", serviceProfileId)
122             List<ServiceInstance> sliceProfileList = []
123             List<Relationship> relationshipList = si.get().getRelationshipList().getRelationship()
124             for (Relationship relationship : relationshipList) {
125                 String relatedTo = relationship.getRelatedTo()
126                 if (relatedTo.toLowerCase() == "service-instance") {
127                     String relatioshipurl = relationship.getRelatedLink()
128                     String instanceId = relatioshipurl.substring(relatioshipurl.lastIndexOf("/") + 1, relatioshipurl.length())
129                     AAIResultWrapper wrapper1 = queryAAI(execution, Types.SERVICE_INSTANCE, instanceId, errorMsg)
130                     Optional<ServiceInstance> serviceInstance = wrapper1.asBean(ServiceInstance.class)
131                     if (serviceInstance.isPresent()) {
132                         ServiceInstance instance = serviceInstance.get()
133                         if ("slice-profile".equalsIgnoreCase(instance.getServiceRole())) {
134                             sliceProfileList.add(instance)
135                         }
136                     }
137                 }
138             }
139             execution.setVariable("sliceProfileList",sliceProfileList)
140             LOGGER.info("serviceInstanceId: ${serviceInstanceId}, snssai: ${snssai}, sliceProfileList: ${sliceProfileList}")
141         }
142         LOGGER.trace(" *****${PREFIX} Exit queryE2ESliceSeriveFromAAI *****")
143         }
144         catch (any)
145         {
146             String msg = "query E2E slice service from aai failed! cause-"+any.getCause()
147             LOGGER.error(any.printStackTrace())
148             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg);
149         }
150     }
151
152     /**
153      * get allotted resource from AAI
154      * save nsi id
155      * @param execution
156      */
157     void getAllottedResFromAAI(DelegateExecution execution)
158     {
159         LOGGER.trace(" *****${PREFIX} Start getAllottedResFromAAI *****")
160         String serviceInstanceId = execution.getVariable("serviceInstanceId")
161         try
162         {
163             String errorMsg = "query allotted resource from aai failed."
164             AAIResultWrapper wrapper = queryAAI(execution, Types.ALLOTTED_RESOURCE, serviceInstanceId, errorMsg)
165             Optional<AllottedResources> ars = wrapper?.asBean(AllottedResources.class)
166             if(ars.isPresent() && ars.get().getAllottedResource())
167             {
168                 List<AllottedResource> allottedResourceList = ars.get().getAllottedResource()
169                 AllottedResource ar = allottedResourceList.first()
170                 String relatedLink = ar?.getRelationshipList()?.getRelationship()?.first()?.getRelatedLink()
171                 String nsiId = relatedLink ? relatedLink.substring(relatedLink.lastIndexOf("/") + 1,relatedLink.length()) : ""
172                 execution.setVariable("nsiId", nsiId)
173                 LOGGER.info("serviceInstanceId: ${serviceInstanceId}, nsiId:${nsiId}")
174             }
175         }
176         catch(BpmnError e){
177             throw e
178         }
179         catch (Exception ex){
180             String msg = "Exception in getAllottedResFromAAI " + ex.getMessage()
181             LOGGER.error(msg)
182             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg)
183         }
184         LOGGER.trace(" *****${PREFIX} Exit getAllottedResFromAAI *****")
185     }
186
187     /**
188      * get nsi service instance from aai
189      * save nssi id
190      * @param execution
191      */
192     void getNSIFromAAI(DelegateExecution execution)
193     {
194         LOGGER.trace(" *****${PREFIX} Start getNSIFromAAI *****")
195         String nsiId = execution.getVariable("nsiId")
196         List<String> nssiIdList = getNSSIIdList(execution, nsiId)
197         String msg = "nsiId: ${nsiId}, nssiIdList:"
198         msg+= nssiIdList.join(",")
199         LOGGER.info(msg)
200         execution.setVariable("nssiIdList", nssiIdList)
201         LOGGER.trace(" *****${PREFIX} Exit getNSIFromAAI *****")
202     }
203     /**
204      * Get NSSI Id from AAI
205      * @param execution
206      * @param nsiId
207      * @return
208      */
209     private List<String> getNSSIIdList(DelegateExecution execution, String nsiId){
210         List<String> nssiIdList = []
211
212         try
213         {
214             String errorMsg = "query nssi from aai failed."
215             AAIResultWrapper wrapper = queryAAI(execution, Types.SERVICE_INSTANCE, nsiId, errorMsg)
216             Optional<ServiceInstance> si = wrapper.asBean(ServiceInstance.class)
217             if(si.isPresent())
218             {
219                 List<Relationship> relationshipList = si.get().getRelationshipList()?.getRelationship()
220                 for (Relationship relationship : relationshipList)
221                 {
222                     String relatedTo = relationship.getRelatedTo()
223                     if (relatedTo == "service-instance")
224                     {
225                         String relatedLink = relationship.getRelatedLink()?:""
226                         String instanceId = relatedLink ? relatedLink.substring(relatedLink.lastIndexOf("/") + 1,relatedLink.length()) : ""
227                         AAIResultWrapper wrapper1 = queryAAI(execution, Types.SERVICE_INSTANCE, instanceId, errorMsg)
228                         Optional<ServiceInstance> serviceInstance = wrapper1.asBean(ServiceInstance.class)
229                         def nssiId
230                         if (serviceInstance.isPresent()) {
231                             ServiceInstance instance = serviceInstance.get()
232                             if ("nssi".equalsIgnoreCase(instance.getServiceRole())) {
233                                 nssiId = instance.getServiceInstanceId()
234                                 nssiIdList.add(nssiId)
235                             }
236                         }
237                     }
238                 }
239             }
240         }
241         catch(BpmnError e){
242             throw e
243         }
244         catch (Exception ex){
245             String msg = "Exception in getNSIFromAAI " + ex.getMessage()
246             LOGGER.error(msg)
247             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, msg)
248         }
249         return nssiIdList
250     }
251
252     /**
253      * get nssi service from AAI
254      * prepare list
255      * @param execution
256      */
257     void getNSSIListFromAAI(DelegateExecution execution)
258     {
259         LOGGER.trace("*****${PREFIX} Start getNSSIListFromAAI *****")
260         List<String> nssiIdList = execution.getVariable("nssiIdList")
261         List<ServiceInstance> nssiInstanceList = []
262         String errorMsg = "query nssi list from aai failed"
263         for(String nssiId : nssiIdList)
264         {
265             AAIResultWrapper wrapper = queryAAI(execution, Types.SERVICE_INSTANCE, nssiId, errorMsg)
266             Optional<ServiceInstance> si =wrapper.asBean(ServiceInstance.class)
267             if(si.isPresent())
268             {
269                 nssiInstanceList.add(si.get())
270             }
271         }
272         int size = nssiInstanceList.size()
273         int proportion = size >0 ?((90/size) as int) : 90
274         execution.setVariable("nssiInstanceList", nssiInstanceList)
275         execution.setVariable("currentNSSIIndex", 0)
276         execution.setVariable("proportion", proportion)
277         String msg ="nssiInstanceList size: ${nssiInstanceList.size()}, proportion:${proportion}"
278         LOGGER.info(msg)
279         LOGGER.trace(" *****${PREFIX} Exit getNSSIListFromAAI *****")
280     }
281
282     /**
283      * get current NSSI
284      * @param execution
285      */
286     void getCurrentNSSI(DelegateExecution execution)
287     {
288         LOGGER.trace(" *****${PREFIX} Start getCurrentNSSI *****")
289         List<ServiceInstance> nssiInstanceList = execution.getVariable("nssiInstanceList")
290         List<ServiceInstance> sliceProfileList = execution.getVariable("sliceProfileList")
291         int currentIndex = execution.getVariable("currentNSSIIndex") as int
292         String profileInstId = ""
293         ServiceInstance nssi = nssiInstanceList?.get(currentIndex)
294         List<Relationship> relationshipList = nssi.getRelationshipList()?.getRelationship()
295         for(ServiceInstance sliceProfileInstance : sliceProfileList) {
296             for (Relationship relationship : relationshipList) {
297                 String relatedTo = relationship.getRelatedTo()
298                 if (relatedTo == "service-instance"){
299                     String relatedLink = relationship.getRelatedLink()?:""
300                     String instanceId = relatedLink ? relatedLink.substring(relatedLink.lastIndexOf("/") + 1,relatedLink.length()) : ""
301                     if(instanceId.equals(sliceProfileInstance.getServiceInstanceId())){
302                         profileInstId = sliceProfileInstance.getServiceInstanceId()
303                         break
304                     }
305                 }
306             }
307             if(profileInstId){
308                 break
309             }
310         }
311
312         //@TODO Temp begin*******************
313 //        AAIPluralResourceUri resourceUri = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.business().customer(execution.getVariable("globalSubscriberId")).serviceSubscription(execution.getVariable("serviceType")).serviceInstance(profileInstId).sliceProfiles())
314 //        AAIResultWrapper wrapper = getAAIClient().get(resourceUri, NotFoundException.class)
315 //        Optional<SliceProfiles> sliceProfilesOpt =wrapper.asBean(SliceProfiles.class)
316 //        SliceProfiles sliceProfiles
317 //        String sliceProfileId
318 //        if(sliceProfilesOpt.isPresent()){
319 //            sliceProfiles = sliceProfilesOpt.get()
320 //            org.onap.aai.domain.yang.SliceProfile sliceProfile = sliceProfiles.getSliceProfile().get(0)
321 //            sliceProfileId = sliceProfile ? sliceProfile.getProfileId() : ""
322 //        }
323         //@TODO Temp end*******************
324
325         def currentNSSI = [:]
326         currentNSSI['nssiServiceInstanceId'] = nssi?.getServiceInstanceId()
327         currentNSSI['modelInvariantId'] = nssi?.getModelInvariantId()
328         currentNSSI['modelVersionId'] = nssi?.getModelVersionId()
329         currentNSSI['nssiName'] = nssi?.getServiceInstanceName()
330         currentNSSI['sST'] = nssi?.getServiceType()
331         currentNSSI['PLMNIdList'] = nssi?.getServiceInstanceLocationId()
332         //@TODO Temp
333
334         currentNSSI['profileId'] =  profileInstId
335 //        currentNSSI['profileId'] =  sliceProfileId
336         currentNSSI['snssai'] = execution.getVariable("snssai") ?: ""
337         currentNSSI['nsiServiceInstanceId'] = execution.getVariable("nsiId") ?: ""
338         currentNSSI['operationId'] = execution.getVariable("operationId") ?: ""
339         currentNSSI['e2eServiceInstanceId'] = execution.getVariable("serviceInstanceId") ?: ""
340         currentNSSI['msoRequestId'] = execution.getVariable("msoRequestId") ?: ""
341         currentNSSI['globalSubscriberId'] = execution.getVariable("globalSubscriberId") ?: ""
342         currentNSSI['serviceType'] = execution.getVariable("serviceType") ?: ""
343         currentNSSI['serviceModelInfo'] = execution.getVariable("serviceModelInfo") ?: ""
344         currentNSSI['proportion'] = (execution.getVariable("proportion") as int)*(currentIndex+1)
345         execution.setVariable("currentNSSI", currentNSSI)
346         String msg = "Now we deal with nssiServiceInstanceId: ${currentNSSI['nssiServiceInstanceId']}, current Index: ${currentIndex}, current proportion:${currentNSSI['proportion']}"
347         LOGGER.info(msg)
348         LOGGER.trace(" *****${PREFIX} Exit getCurrentNSSI *****")
349     }
350
351     /**
352      * parse next nssi
353      * @param execution
354      */
355     void parseNextNSSI(DelegateExecution execution)
356     {
357         LOGGER.trace(" *****${PREFIX} Start parseNextNSSI *****")
358         if(execution.getVariable("WorkflowException") != null){
359             exceptionUtil.buildAndThrowWorkflowException(execution, 7000, "current job failure!")
360         }
361         def currentIndex = execution.getVariable("currentNSSIIndex")
362         List<ServiceInstance> nssiInstanceList = execution.getVariable("nssiInstanceList")
363         def nextIndex = ++currentIndex
364         LOGGER.info("nextIndex: ${nextIndex}")
365         if(nextIndex >= nssiInstanceList.size()){
366             execution.setVariable("isAllNSSIFinished", "true")
367         }else{
368             execution.setVariable("isAllNSSIFinished", "false")
369             execution.setVariable("currentNSSIIndex", nextIndex)
370         }
371         LOGGER.trace(" *****${PREFIX} Exit parseNextNSSI *****")
372     }
373
374     /**
375      * query AAI
376      * @param execution
377      * @param aaiObjectName
378      * @param instanceId
379      * @return AAIResultWrapper
380      */
381     private AAIResultWrapper queryAAI(DelegateExecution execution, AAIObjectName aaiObjectName, String instanceId, String errorMsg)
382     {
383         LOGGER.trace(" *****${PREFIX} Start queryAAI *****")
384         String globalSubscriberId = execution.getVariable("globalSubscriberId")
385         String serviceType = execution.getVariable("serviceType")
386
387         org.onap.aaiclient.client.generated.fluentbuilders.ServiceInstance serviceInstanceType = AAIFluentTypeBuilder.business().customer(globalSubscriberId).serviceSubscription(serviceType).serviceInstance(instanceId)
388         def type
389         if (aaiObjectName == Types.ALLOTTED_RESOURCE) {
390             type = serviceInstanceType.allottedResources()
391         } else if (aaiObjectName == Types.SLICE_PROFILES) {
392             type = serviceInstanceType.sliceProfiles()
393         } else {
394             type = serviceInstanceType
395         }
396         def uri = AAIUriFactory.createResourceUri(type)
397         if (!getAAIClient().exists(uri)) {
398             exceptionUtil.buildAndThrowWorkflowException(execution, 2500, errorMsg)
399         }
400         AAIResultWrapper wrapper = getAAIClient().get(uri, NotFoundException.class)
401         LOGGER.trace(" *****${PREFIX} Exit queryAAI *****")
402         return wrapper
403     }
404
405     void terminateNSIQuery(DelegateExecution execution)
406     {
407         LOGGER.debug("Start terminateNSIQuery")
408
409         //return
410
411         //To test
412         String requestId = execution.getVariable("msoRequestId")
413         String nxlId = execution.getVariable("nsiId")
414         //String nxlId = currentNSSI['nsiServiceInstanceId']
415         String nxlType = "NSI"
416         String messageType = "nsiTerminationResponse"
417         String serviceInstanceId = execution.getVariable("serviceInstanceId")
418         
419         def authHeader = ""
420         String basicAuth = UrnPropertiesReader.getVariable("mso.oof.auth", execution)
421         String msokey = UrnPropertiesReader.getVariable("mso.msoKey", execution)
422
423         String basicAuthValue = utils.encrypt(basicAuth, msokey)
424         if (basicAuthValue != null) {
425             LOGGER.debug( "Obtained BasicAuth username and password for OOF: " + basicAuthValue)
426             try {
427                 authHeader = utils.getBasicAuth(basicAuthValue, msokey)
428                 execution.setVariable("BasicAuthHeaderValue", authHeader)
429             } catch (Exception ex) {
430                 LOGGER.debug( "Unable to encode username and password string: " + ex)
431                 exceptionUtil.buildAndThrowWorkflowException(execution, 401, "Internal Error - Unable to " +
432                         "encode username and password string")
433             }
434         } else {
435             LOGGER.debug( "Unable to obtain BasicAuth - BasicAuth value null")
436             exceptionUtil.buildAndThrowWorkflowException(execution, 401, "Internal Error - BasicAuth " +
437                     "value null")
438         }
439         String oofUrl = UrnPropertiesReader.getVariable("mso.adapters.oof.endpoint", execution)
440         URL requestUrl = new URL(oofUrl)
441         String oofRequest = oofUtils.buildTerminateNxiRequest(requestId, nxlId, nxlType, messageType, serviceInstanceId)
442         OofRequest oofPayload = new OofRequest()
443         oofPayload.setApiPath("/api/oof/terminate/nxi/v1")
444         oofPayload.setRequestDetails(oofRequest)
445         ObjectMapper objectMapper = new ObjectMapper()
446         String requestJson = objectMapper.writeValueAsString(oofPayload)
447         HttpClient httpClient = new HttpClientFactory().newJsonClient(requestUrl, ONAPComponents.OOF)
448         httpClient.addAdditionalHeader("Authorization", authHeader)
449         Response httpResponse = httpClient.post(requestJson)
450
451         int responseCode = httpResponse.getStatus()
452         LOGGER.debug("OOF sync response code is: " + responseCode)
453
454         if(responseCode != 200){
455             exceptionUtil.buildAndThrowWorkflowException(execution, responseCode, "Received a Bad Sync Response from OOF.")
456         }       
457         try {
458             Map<String, String> resMap = httpResponse.readEntity(Map.class)
459             boolean terminateResponse = resMap.get("terminateResponse")
460             execution.setVariable("terminateNSI", terminateResponse)
461         } catch (Exception ex) {
462             LOGGER.debug( "Failed to get terminate Response suggested by OOF.")
463             exceptionUtil.buildAndThrowWorkflowException(execution, 401, "Failed to get terminate Response suggested by OOF.")
464         }
465         LOGGER.debug("Finish terminateNSIQuery")
466     }
467
468
469     /**
470      * If no nssi,delete NSI from AAI
471      * @param execution
472      */
473     void deleteNSIInstance(DelegateExecution execution){
474         def currentNSSI = execution.getVariable("currentNSSI")
475         def nsiId = currentNSSI['nsiServiceInstanceId']
476         List<String> nssiIdList = getNSSIIdList(execution, nsiId)
477         try
478         {
479             if(0 == nssiIdList.size()){
480                 AAIResourceUri serviceInstanceUri = AAIUriFactory.createResourceUri(AAIFluentTypeBuilder.business().customer(execution.getVariable("globalSubscriberId")).serviceSubscription(execution.getVariable("serviceType")).serviceInstance(nsiId))
481                 getAAIClient().delete(serviceInstanceUri)
482             }
483         } catch (Exception ex) {
484             LOGGER.debug( "Failed to delete NSI instance.")
485             exceptionUtil.buildAndThrowWorkflowException(execution, 401, "Failed to delete NSI instance.")
486         }
487
488     }
489 }