Retry traverse membership changes directly

This commit is contained in:
Meik
2026-03-18 15:42:54 +01:00
parent b636f454cf
commit e087eb4197

View File

@@ -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());