Retry traverse membership changes directly
This commit is contained in:
@@ -711,10 +711,6 @@ namespace C4IT_IAM_SET
|
|||||||
if (i == lvl)
|
if (i == lvl)
|
||||||
{
|
{
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene.");
|
DefaultLogger.LogEntry(LogLevels.Debug, "Verarbeite SecurityGroups bei oberster Ebene.");
|
||||||
if (!WhatIf)
|
|
||||||
{
|
|
||||||
WaitForNewGlobalGroupsToBecomeResolvable(domainContext);
|
|
||||||
}
|
|
||||||
foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups)
|
foreach (var currentSecGroup in newSecurityGroups.IAM_SecurityGroups)
|
||||||
{
|
{
|
||||||
if (currentSecGroup == null)
|
if (currentSecGroup == null)
|
||||||
@@ -722,39 +718,17 @@ namespace C4IT_IAM_SET
|
|||||||
DefaultLogger.LogEntry(LogLevels.Error, "currentSecGroup ist null.");
|
DefaultLogger.LogEntry(LogLevels.Error, "currentSecGroup ist null.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
using (GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, currentSecGroup.UID))
|
if (currentSecGroup.Scope != GroupScope.Global)
|
||||||
{
|
continue;
|
||||||
if (groupPrincipal == null)
|
|
||||||
{
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"GroupPrincipal nicht gefunden für UID: {currentSecGroup.UID}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentSecGroup.Scope == GroupScope.Global)
|
if (WhatIf)
|
||||||
{
|
{
|
||||||
try
|
resultToken.warnings.Add($"Traverse-Gruppe '{parentTraverseGroup.Name}' würde Mitglied '{currentSecGroup.Name}' erhalten.");
|
||||||
{
|
continue;
|
||||||
if (!parentTraverseGroup.Members.Contains(groupPrincipal))
|
|
||||||
{
|
|
||||||
if (WhatIf)
|
|
||||||
{
|
|
||||||
resultToken.warnings.Add($"Traverse-Gruppe '{parentTraverseGroup.Name}' würde Mitglied '{groupPrincipal.Name}' erhalten.");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {groupPrincipal.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu");
|
|
||||||
parentTraverseGroup.Members.Add(groupPrincipal);
|
|
||||||
parentTraverseGroup.Save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Error, $"Fehler beim Hinzufügen der Gruppe: {ex.Message}");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!TryEnsureGlobalGroupMembershipWithRetry(domainContext, parentTraverseGroup, currentSecGroup))
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
traverseGroup = parentTraverseGroup;
|
traverseGroup = parentTraverseGroup;
|
||||||
}
|
}
|
||||||
@@ -772,9 +746,8 @@ namespace C4IT_IAM_SET
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {traverseGroup.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu");
|
if (!TryEnsureNestedTraverseGroupMembershipWithRetry(parentTraverseGroup, traverseGroup))
|
||||||
parentTraverseGroup.Members.Add(traverseGroup);
|
continue;
|
||||||
parentTraverseGroup.Save();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -832,32 +805,66 @@ namespace C4IT_IAM_SET
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WaitForNewGlobalGroupsToBecomeResolvable(PrincipalContext domainContext)
|
private bool TryEnsureGlobalGroupMembershipWithRetry(PrincipalContext domainContext, GroupPrincipal parentTraverseGroup, IAM_SecurityGroup currentSecGroup)
|
||||||
{
|
{
|
||||||
if (WhatIf || domainContext == null || newSecurityGroups?.IAM_SecurityGroups == null)
|
if (domainContext == null || parentTraverseGroup == null || currentSecGroup == null || string.IsNullOrWhiteSpace(currentSecGroup.UID))
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
var pendingGroups = newSecurityGroups.IAM_SecurityGroups
|
return RetryTraverseMembershipAction(
|
||||||
.Where(group => group != null
|
currentSecGroup.Name,
|
||||||
&& group.Scope == GroupScope.Global
|
currentSecGroup.CreatedNewEntry,
|
||||||
&& group.CreatedNewEntry
|
() =>
|
||||||
&& !string.IsNullOrWhiteSpace(group.UID))
|
{
|
||||||
.ToList();
|
using (var groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, IdentityType.Sid, currentSecGroup.UID))
|
||||||
if (pendingGroups.Count == 0)
|
{
|
||||||
return;
|
if (groupPrincipal == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
var pendingNames = pendingGroups
|
if (parentTraverseGroup.Members.Contains(groupPrincipal))
|
||||||
.Select(group => group.Name)
|
return true;
|
||||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
|
||||||
.ToList();
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {groupPrincipal.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu");
|
||||||
var retryDelaysMs = new[] { 0, 250, 500, 1000, 2000, 5000 };
|
parentTraverseGroup.Members.Add(groupPrincipal);
|
||||||
|
parentTraverseGroup.Save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryEnsureNestedTraverseGroupMembershipWithRetry(GroupPrincipal parentTraverseGroup, GroupPrincipal traverseGroup)
|
||||||
|
{
|
||||||
|
if (parentTraverseGroup == null || traverseGroup == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return RetryTraverseMembershipAction(
|
||||||
|
traverseGroup.Name,
|
||||||
|
true,
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
if (parentTraverseGroup.Members.Contains(traverseGroup))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Füge {traverseGroup.DistinguishedName} zur Traverse-Gruppe {parentTraverseGroup.DistinguishedName} hinzu");
|
||||||
|
parentTraverseGroup.Members.Add(traverseGroup);
|
||||||
|
parentTraverseGroup.Save();
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool RetryTraverseMembershipAction(string memberName, bool allowRetry, Func<bool> tryAction)
|
||||||
|
{
|
||||||
|
if (tryAction == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var retryDelaysMs = allowRetry
|
||||||
|
? new[] { 0, 250, 500, 1000, 2000, 5000 }
|
||||||
|
: new[] { 0 };
|
||||||
var delayIndex = 0;
|
var delayIndex = 0;
|
||||||
var maxWait = TimeSpan.FromMinutes(3);
|
var maxWait = allowRetry ? TimeSpan.FromMinutes(3) : TimeSpan.Zero;
|
||||||
var waitStopwatch = Stopwatch.StartNew();
|
var waitStopwatch = Stopwatch.StartNew();
|
||||||
|
Exception lastException = null;
|
||||||
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Warte auf neue globale Gruppen fuer Traverse-Verschachtelung: {string.Join(", ", pendingNames)}");
|
while (true)
|
||||||
|
|
||||||
while (pendingGroups.Count > 0 && waitStopwatch.Elapsed < maxWait)
|
|
||||||
{
|
{
|
||||||
var delayMs = retryDelaysMs[Math.Min(delayIndex, retryDelaysMs.Length - 1)];
|
var delayMs = retryDelaysMs[Math.Min(delayIndex, retryDelaysMs.Length - 1)];
|
||||||
if (delayMs > 0)
|
if (delayMs > 0)
|
||||||
@@ -865,43 +872,30 @@ namespace C4IT_IAM_SET
|
|||||||
if (delayIndex < retryDelaysMs.Length - 1)
|
if (delayIndex < retryDelaysMs.Length - 1)
|
||||||
delayIndex++;
|
delayIndex++;
|
||||||
|
|
||||||
for (var index = pendingGroups.Count - 1; index >= 0; index--)
|
try
|
||||||
{
|
{
|
||||||
var pendingGroup = pendingGroups[index];
|
if (tryAction())
|
||||||
try
|
|
||||||
{
|
{
|
||||||
using (var groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, IdentityType.Sid, pendingGroup.UID))
|
if (waitStopwatch.ElapsedMilliseconds > 0)
|
||||||
{
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Traverse-Mitgliedschaft für '{memberName}' nach {waitStopwatch.Elapsed.TotalSeconds:F1}s erfolgreich.");
|
||||||
if (groupPrincipal == null)
|
return true;
|
||||||
continue;
|
|
||||||
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue globale Gruppe fuer Traverse-Verarbeitung aufloesbar: {pendingGroup.Name}");
|
|
||||||
pendingGroups.RemoveAt(index);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue globale Gruppe '{pendingGroup.Name}' noch nicht aufloesbar: {ex.Message}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
lastException = ex;
|
||||||
|
DefaultLogger.LogEntry(LogLevels.Debug, $"Traverse-Mitgliedschaft für '{memberName}' noch nicht möglich: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!allowRetry || waitStopwatch.Elapsed >= maxWait)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pendingGroups.Count > 0)
|
var suffix = lastException == null ? string.Empty : $" Letzte Exception: {lastException.Message}";
|
||||||
{
|
DefaultLogger.LogEntry(LogLevels.Warning, $"Traverse-Mitgliedschaft für '{memberName}' konnte nach {waitStopwatch.Elapsed.TotalSeconds:F1}s nicht sichergestellt werden.{suffix}");
|
||||||
var unresolvedNames = pendingGroups
|
return false;
|
||||||
.Select(group => group.Name)
|
|
||||||
.Where(name => !string.IsNullOrWhiteSpace(name))
|
|
||||||
.ToList();
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Warning, $"Nicht alle neuen globalen Gruppen waren nach {waitStopwatch.Elapsed.TotalSeconds:F1}s fuer Traverse-Verarbeitung aufloesbar: {string.Join(", ", unresolvedNames)}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DefaultLogger.LogEntry(LogLevels.Debug, $"Neue globale Gruppen nach {waitStopwatch.Elapsed.TotalSeconds:F1}s fuer Traverse-Verarbeitung aufloesbar.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private ResultToken checkFolder()
|
private ResultToken checkFolder()
|
||||||
{
|
{
|
||||||
LogMethodBegin(MethodBase.GetCurrentMethod());
|
LogMethodBegin(MethodBase.GetCurrentMethod());
|
||||||
|
|||||||
Reference in New Issue
Block a user