Add NTFS automatic ensure timeout diagnostics
This commit is contained in:
@@ -5,6 +5,7 @@ using C4IT_IAM_Engine;
|
||||
using LiamAD;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
@@ -77,6 +78,9 @@ namespace LiamWorkflowActivities
|
||||
|
||||
public static class LiamWorkflowRuntime
|
||||
{
|
||||
private const string AutomaticNtfsEnsureTimeoutSecondsKey = "NtfsAutomaticEnsureTimeoutSeconds";
|
||||
private const int DefaultAutomaticNtfsEnsureTimeoutSeconds = 300;
|
||||
|
||||
public static async Task<GetDataAreasOperationResult> GetDataAreasFromProviderAsync(cLiamProviderBase provider, string configurationId = null, bool? simulateConfiguredNtfsPermissionEnsure = null)
|
||||
{
|
||||
var result = new GetDataAreasOperationResult();
|
||||
@@ -422,11 +426,19 @@ namespace LiamWorkflowActivities
|
||||
var allowFolderEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsPermissionGroups");
|
||||
var allowSharePathEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsPermissionGroupsForShares");
|
||||
var allowTraverseEnsure = IsAdditionalConfigurationEnabled(provider, "EnsureNtfsTraverseGroups");
|
||||
var ensureTimeoutSeconds = GetAdditionalConfigurationInt32(
|
||||
provider,
|
||||
AutomaticNtfsEnsureTimeoutSecondsKey,
|
||||
DefaultAutomaticNtfsEnsureTimeoutSeconds,
|
||||
0);
|
||||
var ensureTimeout = ensureTimeoutSeconds > 0
|
||||
? TimeSpan.FromSeconds(ensureTimeoutSeconds)
|
||||
: TimeSpan.Zero;
|
||||
if (!allowFolderEnsure && !allowSharePathEnsure && !allowTraverseEnsure)
|
||||
return true;
|
||||
|
||||
LogEntry(
|
||||
$"Automatic NTFS ensure configured. PermissionGroups={allowFolderEnsure}, PermissionGroupsForShares={allowSharePathEnsure}, TraverseGroups={allowTraverseEnsure}, DataAreas={dataAreas.Count}, WhatIf={simulateOnly}",
|
||||
$"Automatic NTFS ensure configured. PermissionGroups={allowFolderEnsure}, PermissionGroupsForShares={allowSharePathEnsure}, TraverseGroups={allowTraverseEnsure}, DataAreas={dataAreas.Count}, WhatIf={simulateOnly}, TimeoutSeconds={ensureTimeoutSeconds}",
|
||||
LogLevels.Debug);
|
||||
|
||||
if (allowFolderEnsure || allowSharePathEnsure)
|
||||
@@ -449,15 +461,19 @@ namespace LiamWorkflowActivities
|
||||
ResultToken ensureResult;
|
||||
try
|
||||
{
|
||||
ensureResult = await ntfsProvider.EnsureMissingPermissionGroupsAsync(
|
||||
ensureResult = await RunAutomaticNtfsEnsureOperationAsync(
|
||||
folderPath,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
allowSharePathEnsure,
|
||||
ensureTraverseInPermissionPhase,
|
||||
simulateOnly);
|
||||
"permission group ensure",
|
||||
() => ntfsProvider.EnsureMissingPermissionGroupsAsync(
|
||||
folderPath,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
allowSharePathEnsure,
|
||||
ensureTraverseInPermissionPhase,
|
||||
simulateOnly),
|
||||
ensureTimeout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -477,6 +493,12 @@ namespace LiamWorkflowActivities
|
||||
|
||||
if (ensureResult.resultErrorId != 0)
|
||||
{
|
||||
if (IsAutomaticNtfsEnsureTimeout(ensureResult))
|
||||
{
|
||||
SetAutomaticEnsureTimeoutError(result, folderPath, ensureResult, "permission group ensure");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogEntry(
|
||||
$"Automatic NTFS permission group ensure skipped for '{folderPath}' after resultErrorId={ensureResult.resultErrorId}. ResultMessage='{ensureResult.resultMessage ?? string.Empty}'",
|
||||
LogLevels.Warning);
|
||||
@@ -514,10 +536,14 @@ namespace LiamWorkflowActivities
|
||||
ResultToken ensureResult;
|
||||
try
|
||||
{
|
||||
ensureResult = await ntfsProvider.EnsureTraverseGroupsAsync(
|
||||
ensureResult = await RunAutomaticNtfsEnsureOperationAsync(
|
||||
folderPath,
|
||||
null,
|
||||
simulateOnly);
|
||||
"traverse group ensure",
|
||||
() => ntfsProvider.EnsureTraverseGroupsAsync(
|
||||
folderPath,
|
||||
null,
|
||||
simulateOnly),
|
||||
ensureTimeout);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -537,6 +563,12 @@ namespace LiamWorkflowActivities
|
||||
|
||||
if (ensureResult.resultErrorId != 0)
|
||||
{
|
||||
if (IsAutomaticNtfsEnsureTimeout(ensureResult))
|
||||
{
|
||||
SetAutomaticEnsureTimeoutError(result, folderPath, ensureResult, "traverse group ensure");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogEntry(
|
||||
$"Automatic NTFS traverse group ensure skipped for '{folderPath}' after resultErrorId={ensureResult.resultErrorId}. ResultMessage='{ensureResult.resultMessage ?? string.Empty}'",
|
||||
LogLevels.Warning);
|
||||
@@ -557,6 +589,55 @@ namespace LiamWorkflowActivities
|
||||
return true;
|
||||
}
|
||||
|
||||
private static async Task<ResultToken> RunAutomaticNtfsEnsureOperationAsync(
|
||||
string folderPath,
|
||||
string operationLabel,
|
||||
Func<Task<ResultToken>> operation,
|
||||
TimeSpan timeout)
|
||||
{
|
||||
var operationTask = Task.Run(operation);
|
||||
#pragma warning disable 4014
|
||||
// Fire-and-forget observer for exceptions that happen after a timeout.
|
||||
operationTask.ContinueWith(
|
||||
task => LogException(task.Exception),
|
||||
TaskContinuationOptions.OnlyOnFaulted);
|
||||
#pragma warning restore 4014
|
||||
|
||||
if (timeout <= TimeSpan.Zero)
|
||||
return await operationTask;
|
||||
|
||||
var completedTask = await Task.WhenAny(operationTask, Task.Delay(timeout));
|
||||
if (completedTask == operationTask)
|
||||
return await operationTask;
|
||||
|
||||
var message =
|
||||
$"Automatic NTFS {operationLabel} timed out for '{folderPath}' after {timeout.TotalSeconds:F0}s. " +
|
||||
"The workflow will stop automatic NTFS ensure processing for this run. " +
|
||||
"The underlying NTFS/AD operation may still finish in the worker process.";
|
||||
LogEntry(message, LogLevels.Error);
|
||||
return new ResultToken("AutomaticNtfsEnsureTimeout")
|
||||
{
|
||||
resultErrorId = 30010,
|
||||
resultMessage = message
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsAutomaticNtfsEnsureTimeout(ResultToken ensureResult)
|
||||
{
|
||||
return ensureResult?.resultErrorId == 30010;
|
||||
}
|
||||
|
||||
private static void SetAutomaticEnsureTimeoutError(
|
||||
GetDataAreasOperationResult result,
|
||||
string folderPath,
|
||||
ResultToken ensureResult,
|
||||
string operationLabel)
|
||||
{
|
||||
result.ErrorCode = "WF_GET_DATAAREAS_ENSURE_NTFS_GROUPS_TIMEOUT";
|
||||
result.ErrorMessage = ensureResult?.resultMessage
|
||||
?? $"Automatic NTFS {operationLabel} timed out for '{folderPath}'.";
|
||||
}
|
||||
|
||||
private static NtfsAutomaticEnsurePreviewEntry MapAutomaticEnsurePreview(string folderPath, ResultToken ensureResult)
|
||||
{
|
||||
return new NtfsAutomaticEnsurePreviewEntry
|
||||
@@ -662,6 +743,33 @@ namespace LiamWorkflowActivities
|
||||
|| rawValue.Equals("yes", StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static int GetAdditionalConfigurationInt32(cLiamProviderBase provider, string key, int defaultValue, int minValue)
|
||||
{
|
||||
if (provider?.AdditionalConfiguration == null || string.IsNullOrWhiteSpace(key))
|
||||
return defaultValue;
|
||||
|
||||
if (!provider.AdditionalConfiguration.TryGetValue(key, out var rawValue) || string.IsNullOrWhiteSpace(rawValue))
|
||||
return defaultValue;
|
||||
|
||||
if (!int.TryParse(rawValue.Trim(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsedValue))
|
||||
{
|
||||
LogEntry(
|
||||
$"AdditionalConfiguration '{key}' has invalid integer value '{rawValue}'. Defaulting to {defaultValue}.",
|
||||
LogLevels.Warning);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
if (parsedValue < minValue)
|
||||
{
|
||||
LogEntry(
|
||||
$"AdditionalConfiguration '{key}' value {parsedValue} is below minimum {minValue}. Defaulting to {defaultValue}.",
|
||||
LogLevels.Warning);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return parsedValue;
|
||||
}
|
||||
|
||||
private static bool IsWorkflowWhatIfEnabled(cLiamProviderBase provider)
|
||||
{
|
||||
return IsAdditionalConfigurationEnabled(provider, "WhatIf");
|
||||
|
||||
Reference in New Issue
Block a user