2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. 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 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 * ============LICENSE_END=========================================================
20 package org.openecomp.mso.bpmn.infrastructure.scripts
22 import groovy.json.JsonOutput
23 import groovy.json.JsonSlurper
24 import groovy.util.Node
25 import groovy.util.XmlParser;
26 import groovy.xml.QName
28 import java.io.Serializable;
29 import java.util.UUID;
30 import org.openecomp.mso.bpmn.common.scripts.ExceptionUtil
31 import org.camunda.bpm.engine.delegate.BpmnError
32 import org.camunda.bpm.engine.impl.cmd.AbstractSetVariableCmd
33 import org.camunda.bpm.engine.delegate.DelegateExecution
34 import org.openecomp.mso.rest.APIResponse
35 import org.openecomp.mso.rest.RESTClient
36 import org.openecomp.mso.rest.RESTConfig
37 import org.openecomp.mso.bpmn.common.scripts.AbstractServiceTaskProcessor;
38 import org.openecomp.mso.bpmn.common.scripts.VidUtils;
39 import org.openecomp.mso.bpmn.core.RollbackData
40 import org.openecomp.mso.bpmn.core.WorkflowException
41 import org.openecomp.mso.bpmn.core.json.JsonUtils
42 import org.openecomp.mso.bpmn.core.domain.ModelInfo
43 import org.openecomp.mso.bpmn.core.domain.ServiceDecomposition
44 import org.openecomp.mso.bpmn.core.domain.VnfResource
45 import org.openecomp.mso.client.aai.*
47 import org.openecomp.mso.client.appc.ApplicationControllerClient;
48 import org.openecomp.mso.client.appc.ApplicationControllerSupport;
49 import org.openecomp.mso.client.aai.AAIResourcesClient
50 import org.openecomp.mso.client.aai.entities.AAIResultWrapper
51 import org.openecomp.mso.client.aai.entities.uri.AAIUri
52 import org.openecomp.mso.client.aai.entities.uri.AAIUriFactory
53 import org.onap.appc.client.lcm.model.Action;
54 import org.onap.appc.client.lcm.model.ActionIdentifiers;
55 import org.onap.appc.client.lcm.model.LockInput
56 import org.onap.appc.client.lcm.model.UnlockInput
57 import org.onap.appc.client.lcm.model.HealthCheckInput
58 import org.onap.appc.client.lcm.model.StartInput
59 import org.onap.appc.client.lcm.model.StopInput
60 import org.onap.appc.client.lcm.model.Flags
61 import org.onap.appc.client.lcm.model.Status
65 public class VnfInPlaceUpdate extends VnfCmBase {
67 ExceptionUtil exceptionUtil = new ExceptionUtil()
68 JsonUtils jsonUtils = new JsonUtils()
69 def prefix = "VnfIPU_"
72 * Initialize the flow's variables.
74 * @param execution The flow's execution instance.
76 public void initProcessVariables(DelegateExecution execution) {
77 execution.setVariable('prefix', 'VnfIPU_')
78 execution.setVariable('Request', null)
79 execution.setVariable('requestInfo', null)
80 execution.setVariable('source', null)
81 execution.setVariable('vnfInputs', null)
82 execution.setVariable('tenantId', null)
83 execution.setVariable('vnfParams', null)
84 execution.setVariable('UpdateVnfSuccessIndicator', false)
85 execution.setVariable('serviceType', null)
86 execution.setVariable('nfRole', null)
87 execution.setVariable('currentActivity', 'VnfIPU')
88 execution.setVariable('workStep', null)
89 execution.setVariable('failedActivity', null)
90 execution.setVariable('errorCode', "0")
91 execution.setVariable('errorText', null)
92 execution.setVariable('healthCheckIndex0', 0)
93 execution.setVariable('healthCheckIndex1', 1)
94 execution.setVariable('maxRetryCount', 3)
95 execution.setVariable("rollbackSetClosedLoopDisabledFlag", false)
96 execution.setVariable("rollbackVnfStop", false)
97 execution.setVariable("rollbackVnfLock", false)
98 execution.setVariable("rollbackQuiesceTraffic", false)
99 execution.setVariable("rollbackSetVnfInMaintenanceFlag", false)
103 * Check for missing elements in the received request.
105 * @param execution The flow's execution instance.
107 public void preProcessRequest(DelegateExecution execution) {
108 def method = getClass().getSimpleName() + '.preProcessRequest(' +
109 'execution=' + execution.getId() +
111 initProcessVariables(execution)
112 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
113 logDebug('Entered ' + method, isDebugLogEnabled)
115 initProcessVariables(execution)
117 def incomingRequest = execution.getVariable('bpmnRequest')
119 utils.log("DEBUG", "Incoming Infra Request: " + incomingRequest, isDebugLogEnabled)
121 def jsonSlurper = new JsonSlurper()
122 def jsonOutput = new JsonOutput()
123 Map reqMap = jsonSlurper.parseText(incomingRequest)
124 utils.log("DEBUG", " Request is in JSON format.", isDebugLogEnabled)
126 def serviceInstanceId = execution.getVariable('serviceInstanceId')
127 def vnfId = execution.getVariable('vnfId')
129 execution.setVariable('serviceInstanceId', serviceInstanceId)
130 execution.setVariable('vnfId', vnfId)
131 execution.setVariable("isVidRequest", "true")
132 execution.setVariable('serviceType', 'Mobility')
133 execution.setVariable('payload', "")
134 execution.setVariable('actionSnapshot', Action.Snapshot)
135 execution.setVariable('actionLock', Action.Lock)
136 execution.setVariable('actionUnlock', Action.Unlock)
137 execution.setVariable('actionUpgradePreCheck', Action.UpgradePreCheck)
138 execution.setVariable('actionUpgradePostCheck', Action.UpgradePostCheck)
139 execution.setVariable('actionQuiesceTraffic', Action.QuiesceTraffic)
140 execution.setVariable('actionUpgradeBackup', Action.UpgradeBackup)
141 execution.setVariable('actionUpgradeSoftware', Action.UpgradeSoftware)
142 execution.setVariable('actionResumeTraffic', Action.ResumeTraffic)
144 def payload = reqMap.requestDetails?.requestParameters?.payload
145 execution.setVariable('payload', payload)
147 utils.log("DEBUG", 'Processed payload: ' + payload, isDebugLogEnabled)
150 def requestId = execution.getVariable("mso-request-id")
151 execution.setVariable('requestId', requestId)
152 execution.setVariable('msoRequestId', requestId)
154 def requestorId = reqMap.requestDetails?.requestInfo?.requestorId ?: null
155 execution.setVariable('requestorId', requestorId)
157 def cloudConfiguration = reqMap.requestDetails?.cloudConfiguration
158 def lcpCloudRegionId = cloudConfiguration.lcpCloudRegionId
159 execution.setVariable('lcpCloudRegionId', lcpCloudRegionId)
160 def tenantId = cloudConfiguration.tenantId
161 execution.setVariable('tenantId', tenantId)
163 execution.setVariable("UpdateVnfInfraSuccessIndicator", false)
165 execution.setVariable("isDebugLogEnabled", isDebugLogEnabled)
167 def source = reqMap.requestDetails?.requestInfo?.source
168 execution.setVariable("source", source)
170 //For Completion Handler & Fallout Handler
172 """<request-info xmlns="http://org.openecomp/mso/infra/vnf-request/v1">
173 <request-id>${requestId}</request-id>
174 <action>UPDATE</action>
175 <source>${source}</source>
178 execution.setVariable("requestInfo", requestInfo)
180 logDebug('RequestInfo: ' + execution.getVariable("requestInfo"), isDebugLogEnabled)
182 logDebug('Exited ' + method, isDebugLogEnabled)
185 catch(groovy.json.JsonException je) {
186 utils.log("DEBUG", " Request is not in JSON format.", isDebugLogEnabled)
187 exceptionUtil.buildAndThrowWorkflowException(execution, 5000, "Invalid request format")
191 String restFaultMessage = e.getMessage()
192 utils.log("ERROR", " Exception Encountered - " + "\n" + restFaultMessage, isDebugLogEnabled)
193 exceptionUtil.buildAndThrowWorkflowException(execution, 5000, restFaultMessage)
198 * Prepare and send the sychronous response for this flow.
200 * @param execution The flow's execution instance.
202 public void sendSynchResponse(DelegateExecution execution) {
203 def method = getClass().getSimpleName() + '.sendSynchResponse(' +
204 'execution=' + execution.getId() +
206 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
207 logDebug('Entered ' + method, isDebugLogEnabled)
211 def requestInfo = execution.getVariable('requestInfo')
212 def requestId = execution.getVariable('requestId')
213 def source = execution.getVariable('source')
214 def progress = getNodeTextForce(requestInfo, 'progress')
215 if (progress.isEmpty()) {
218 def startTime = getNodeTextForce(requestInfo, 'start-time')
219 if (startTime.isEmpty()) {
220 startTime = System.currentTimeMillis()
223 // RESTResponse (for API Handler (APIH) Reply Task)
224 def vnfId = execution.getVariable("vnfId")
225 String synchResponse = """{"requestReferences":{"instanceId":"${vnfId}","requestId":"${requestId}"}}""".trim()
227 sendWorkflowResponse(execution, 200, synchResponse)
229 logDebug('Exited ' + method, isDebugLogEnabled)
230 } catch (BpmnError e) {
232 } catch (Exception e) {
233 logError('Caught exception in ' + method, e)
234 exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in sendResponse(): ' + e.getMessage())
240 * Check if this VNF is already in maintenance in A&AI.
243 * @param execution The flow's execution instance.
245 public void checkIfVnfInMaintInAAI(DelegateExecution execution) {
246 def method = getClass().getSimpleName() + '.checkIfVnfInMaintInAAI(' +
247 'execution=' + execution.getId() +
249 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
250 execution.setVariable('errorCode', "0")
251 execution.setVariable("workStep", "checkIfVnfInMaintInAAI")
252 execution.setVariable("failedActivity", "AAI")
253 logDebug('Entered ' + method, isDebugLogEnabled)
256 def transactionLoggingUuid = UUID.randomUUID().toString()
257 AAIRestClientImpl client = new AAIRestClientImpl()
258 AAIValidatorImpl aaiValidator = new AAIValidatorImpl()
259 aaiValidator.setClient(client)
260 def vnfId = execution.getVariable("vnfId")
261 boolean isInMaint = aaiValidator.isVNFLocked(vnfId, transactionLoggingUuid)
262 logDebug("isInMaint result: " + isInMaint, isDebugLogEnabled)
263 execution.setVariable('isVnfInMaintenance', isInMaint)
266 execution.setVariable("errorCode", "1003")
267 execution.setVariable("errorText", "VNF is in maintenance in A&AI")
271 logDebug('Exited ' + method, isDebugLogEnabled)
272 } catch (BpmnError e) {
274 } catch (Exception e) {
275 logError('Caught exception in ' + method, e)
276 execution.setVariable("errorCode", "1002")
277 execution.setVariable("errorText", e.getMessage())
278 //exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in checkIfVnfInMaintInAAI(): ' + e.getMessage())
284 * Check if this VNF's pservers are locked in A&AI.
287 * @param execution The flow's execution instance.
289 public void checkIfPserversInMaintInAAI(DelegateExecution execution) {
290 def method = getClass().getSimpleName() + '.checkIfPserversInMaintInAAI(' +
291 'execution=' + execution.getId() +
293 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
294 execution.setVariable('errorCode', "0")
295 logDebug('Entered ' + method, isDebugLogEnabled)
296 execution.setVariable("workStep", "checkIfPserversInMaintInAAI")
297 execution.setVariable("failedActivity", "AAI")
300 def transactionLoggingUuid = UUID.randomUUID().toString()
301 AAIRestClientImpl client = new AAIRestClientImpl()
302 AAIValidatorImpl aaiValidator = new AAIValidatorImpl()
303 aaiValidator.setClient(client)
304 def vnfId = execution.getVariable("vnfId")
305 boolean areLocked = aaiValidator.isPhysicalServerLocked(vnfId, transactionLoggingUuid)
306 logDebug("areLocked result: " + areLocked, isDebugLogEnabled)
307 execution.setVariable('arePserversLocked', areLocked)
310 execution.setVariable("errorCode", "1003")
311 execution.setVariable("errorText", "pServers are locked in A&AI")
314 logDebug('Exited ' + method, isDebugLogEnabled)
315 } catch (BpmnError e) {
317 } catch (Exception e) {
318 logError('Caught exception in ' + method, e)
319 execution.setVariable("errorCode", "1002")
320 execution.setVariable("errorText", e.getMessage())
321 //exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in checkIfPserversInMaintInAAI(): ' + e.getMessage())
326 * Set inMaint flag for this VNF to the specified value in A&AI.
329 * @param execution The flow's execution instance.
330 * @param inMaint The boolean value of the flag to set
332 public void setVnfInMaintFlagInAAI(DelegateExecution execution, boolean inMaint) {
333 def method = getClass().getSimpleName() + '.setVnfInMaintFlagInAAI(' +
334 'execution=' + execution.getId() +
336 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
337 execution.setVariable('errorCode', "0")
338 logDebug('Entered ' + method, isDebugLogEnabled)
340 execution.setVariable("workStep", "setVnfInMaintFlagInAAI")
343 execution.setVariable("workStep", "unsetVnfInMaintFlagInAAI")
345 execution.setVariable("failedActivity", "AAI")
348 def transactionLoggingUuid = UUID.randomUUID().toString()
349 AAIRestClientImpl client = new AAIRestClientImpl()
350 AAIUpdatorImpl aaiUpdator = new AAIUpdatorImpl()
351 aaiUpdator.setClient(client)
352 def vnfId = execution.getVariable("vnfId")
354 aaiUpdator.updateVnfToLocked(vnfId, transactionLoggingUuid)
355 execution.setVariable("rollbackSetVnfInMaintenanceFlag", true)
358 aaiUpdator.updateVnfToUnLocked(vnfId, transactionLoggingUuid)
361 logDebug('Exited ' + method, isDebugLogEnabled)
362 } catch (BpmnError e) {
364 } catch (Exception e) {
365 logError('Caught exception in ' + method, e)
366 execution.setVariable("errorCode", "1002")
367 execution.setVariable("errorText", e.getMessage())
368 //exceptionUtil.buildAndThrowWorkflowException(execution, 1002, 'Error in setVnfInMaintFlagInAAI(): ' + e.getMessage())
373 * Check if VF Closed Loop Disabled in A&AI.
376 * @param execution The flow's execution instance.
378 public void checkIfClosedLoopDisabledInAAI(DelegateExecution execution) {
379 def method = getClass().getSimpleName() + '.checkIfClosedLoopDisabledInAAI(' +
380 'execution=' + execution.getId() +
382 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
383 execution.setVariable('errorCode', "0")
384 execution.setVariable("workStep", "checkClosedLoopDisabledFlagInAAI")
385 execution.setVariable("failedActivity", "AAI")
386 logDebug('Entered ' + method, isDebugLogEnabled)
389 def transactionLoggingUuid = UUID.randomUUID().toString()
390 def vnfId = execution.getVariable("vnfId")
391 logDebug("vnfId is: " + vnfId, isDebugLogEnabled)
392 AAIResourcesClient client = new AAIResourcesClient()
393 AAIUri genericVnfUri = AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId)
394 AAIResultWrapper aaiRW = client.get(genericVnfUri)
395 Map<String, Object> result = aaiRW.asMap()
396 boolean isClosedLoopDisabled = result.getOrDefault("is-closed-loop-disabled", false)
398 logDebug("isClosedLoopDisabled result: " + isClosedLoopDisabled, isDebugLogEnabled)
399 execution.setVariable('isClosedLoopDisabled', isClosedLoopDisabled)
401 if (isClosedLoopDisabled) {
402 execution.setVariable("errorCode", "1004")
403 execution.setVariable("errorText", "closedLoop is disabled in A&AI")
406 logDebug('Exited ' + method, isDebugLogEnabled)
407 } catch (BpmnError e) {
409 } catch (Exception e) {
410 logError('Caught exception in ' + method, e)
411 execution.setVariable("errorCode", "1002")
412 execution.setVariable("errorText", e.getMessage())
417 * Set VF Closed Loop Disabled Flag in A&AI.
420 * @param execution The flow's execution instance.
422 public void setClosedLoopDisabledInAAI(DelegateExecution execution, boolean setDisabled) {
423 def method = getClass().getSimpleName() + '.setClosedLoopDisabledInAAI(' +
424 'execution=' + execution.getId() +
426 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
427 execution.setVariable('errorCode', "0")
429 execution.setVariable("workStep", "setClosedLoopDisabledFlagInAAI")
430 execution.setVariable("rollbackSetClosedLoopDisabledFlag", true)
433 execution.setVariable("workStep", "unsetClosedLoopDisabledFlagInAAI")
436 execution.setVariable("failedActivity", "AAI")
437 logDebug('Entered ' + method, isDebugLogEnabled)
440 def transactionLoggingUuid = UUID.randomUUID().toString()
441 def vnfId = execution.getVariable("vnfId")
442 AAIResourcesClient client = new AAIResourcesClient()
443 AAIUri genericVnfUri = AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId)
445 Map<String, Boolean> request = new HashMap<>()
446 request.put("is-closed-loop-disabled", setDisabled)
447 client.update(genericVnfUri, request)
448 logDebug("set isClosedLoop to: " + setDisabled, isDebugLogEnabled)
450 logDebug('Exited ' + method, isDebugLogEnabled)
451 } catch (BpmnError e) {
453 } catch (Exception e) {
454 logError('Caught exception in ' + method, e)
455 execution.setVariable("errorCode", "1002")
456 execution.setVariable("errorText", e.getMessage())
464 * Call APP-C client to execute specified APP-C command for this VNF.
467 * @param execution The flow's execution instance.
468 * @param action The action to take in APP-C.
470 public void runAppcCommand(DelegateExecution execution, Action action) {
471 def method = getClass().getSimpleName() + '.runAppcCommand(' +
472 'execution=' + execution.getId() +
474 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
475 execution.setVariable('errorCode', "0")
476 logDebug('Entered ' + method, isDebugLogEnabled)
478 ApplicationControllerClient appcClient = null
481 logDebug("Running APP-C action: " + action.toString(), isDebugLogEnabled)
482 String vnfId = execution.getVariable('vnfId')
483 String msoRequestId = execution.getVariable('requestId')
484 execution.setVariable('msoRequestId', msoRequestId)
485 execution.setVariable("failedActivity", "APP-C")
487 appcClient = new ApplicationControllerClient()
488 ApplicationControllerSupport support = new ApplicationControllerSupport()
489 appcClient.appCSupport=support
490 org.springframework.test.util.ReflectionTestUtils.setField(support, "lcmModelPackage", "org.onap.appc.client.lcm.model");
491 Flags flags = new Flags();
492 ActionIdentifiers actionIdentifiers = new ActionIdentifiers();
493 actionIdentifiers.setVnfId(vnfId);
497 execution.setVariable('workStep', "LockVNF")
498 appcStatus = appcClient.runCommand(Action.Lock,actionIdentifiers,null,msoRequestId)
501 execution.setVariable('workStep', "UnlockVNF")
502 appcStatus = appcClient.runCommand(Action.Unlock,actionIdentifiers,null,msoRequestId)
504 case Action.HealthCheck:
505 def healthCheckIndex = execution.getVariable('healthCheckIndex')
506 execution.setVariable('workStep', "HealthCheckVNF" + healthCheckIndex)
507 execution.setVariable('healthCheckIndex', healthCheckIndex + 1)
508 appcStatus = appcClient.runCommand(Action.HealthCheck,actionIdentifiers,null,msoRequestId)
511 execution.setVariable('workStep', "StartVNF")
512 appcStatus = appcClient.runCommand(Action.Start,actionIdentifiers,null,msoRequestId)
515 execution.setVariable('workStep', "StopVNF")
516 appcStatus = appcClient.runCommand(Action.Stop,actionIdentifiers,null,msoRequestId)
521 logDebug("Completed AppC request", isDebugLogEnabled)
522 int appcCode = appcStatus.getCode()
523 logDebug("AppC status code is: " + appcCode, isDebugLogEnabled)
524 logDebug("AppC status message is: " + appcStatus.getMessage(), isDebugLogEnabled)
525 if (support.getCategoryOf(appcStatus) == ApplicationControllerSupport.StatusCategory.ERROR) {
526 execution.setVariable("errorCode", Integer.toString(appcCode))
527 execution.setVariable("errorText", appcStatus.getMessage())
530 logDebug('Exited ' + method, isDebugLogEnabled)
531 } catch (BpmnError e) {
532 logError('Caught exception in ' + method, e)
533 execution.setVariable("errorCode", "1002")
534 execution.setVariable("errorText", e.getMessage())
536 } catch (java.lang.NoSuchMethodError e) {
537 logError('Caught exception in ' + method, e)
538 execution.setVariable("errorCode", "1002")
539 execution.setVariable("errorText", e.getMessage())
541 } catch (Exception e) {
542 logError('Caught exception in ' + method, e)
543 execution.setVariable("errorCode", "1002")
544 execution.setVariable("errorText", e.getMessage())
550 * Placeholder for a call to APP-C client to execute specified APP-C command for this VNF.
553 * @param execution The flow's execution instance.
554 * @param action The action to take in APP-C.
556 public void runAppcCommandPlaceholder(DelegateExecution execution, String action) {
557 def method = getClass().getSimpleName() + '.runAppcCommandPlaceholder(' +
558 'execution=' + execution.getId() +
560 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
561 execution.setVariable('errorCode', "0")
562 logDebug('Entered ' + method, isDebugLogEnabled)
563 execution.setVariable("failedActivity", "APP-C")
564 execution.setVariable("workStep", action)
570 * Handle Abort disposition from RainyDayHandler
572 * @param execution The flow's execution instance.
574 public void abortProcessing(DelegateExecution execution) {
575 def method = getClass().getSimpleName() + '.abortProcessing(' +
576 'execution=' + execution.getId() +
578 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
579 logDebug('Entered ' + method, isDebugLogEnabled)
581 def errorText = execution.getVariable("errorText")
582 def errorCode = execution.getVariable("errorCode")
584 exceptionUtil.buildAndThrowWorkflowException(execution, errorCode as Integer, errorText)
588 * Increment Retry Count for Current Work Step
590 * @param execution The flow's execution instance.
592 public void incrementRetryCount(DelegateExecution execution) {
593 def method = getClass().getSimpleName() + '.incrementRetryCount(' +
594 'execution=' + execution.getId() +
596 def isDebugLogEnabled = execution.getVariable('isDebugLogEnabled')
597 logDebug('Entered ' + method, isDebugLogEnabled)
599 String retryCountVariableName = execution.getVariable("workStep") + "RetryCount"
600 execution.setVariable("retryCountVariableName", retryCountVariableName)
602 def retryCountVariable = execution.getVariable(retryCountVariableName)
605 if (retryCountVariable != null) {
606 retryCount = (int) retryCountVariable
611 execution.setVariable(retryCountVariableName, retryCount)
613 logDebug("value of " + retryCountVariableName + " is " + retryCount, isDebugLogEnabled)
614 logDebug('Exited ' + method, isDebugLogEnabled)