From 52aff4b2bbccceabfdde2015aec8a9222aa45926 Mon Sep 17 00:00:00 2001 From: "Francois @fanf42 Armand" Date: Tue, 23 Apr 2024 16:39:40 +0200 Subject: [PATCH] Fixes #24772: RuleTarget compliance is very slow to compute --- .../rudder/domain/policies/RuleTarget.scala | 48 ++++++++----------- .../repository/NodeGroupRepository.scala | 2 +- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/policies/RuleTarget.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/policies/RuleTarget.scala index 4b6393c57a4..44f628cc175 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/policies/RuleTarget.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/domain/policies/RuleTarget.scala @@ -292,20 +292,23 @@ object RuleTarget extends Loggable { * allNodes pair is: (nodeid, isPolicyServer) */ def getNodeIdsChunk( - targets: Set[RuleTarget], - allNodes: Map[NodeId, Boolean /* isPolicyServer */ ], - groups: Map[NodeGroupId, Chunk[NodeId]], - allNodesAreThere: Boolean = true // if we are working on a subset of node, set to false + targets: Set[RuleTarget], + allNodes: Map[NodeId, Boolean /* isPolicyServer */ ], + groups: Map[NodeGroupId, Chunk[NodeId]] ): Chunk[NodeId] = { - val result = getNodeIdsChunkRec(Chunk.fromIterable(targets), allNodes, groups, allNodesAreThere) - result.distinct + val result = getNodeIdsChunkRec(Chunk.fromIterable(targets), allNodes.toMap, groups) + + // we always must intersect with the keySet of nodes, because sometime node ids in groups is a super set + // of the given allNodes, for ex! + // - for static group where some of the nodes were deleted, + // - when we have tenants (Rudder 8.1+= + Chunk.fromIterable(result.toSet.intersect(allNodes.keySet)) } def getNodeIdsChunkRec( - targets: Chunk[RuleTarget], - allNodes: Map[NodeId, Boolean /* isPolicyServer */ ], - groups: Map[NodeGroupId, Chunk[NodeId]], - allNodesAreThere: Boolean = true // if we are working on a subset of node, set to false + targets: Chunk[RuleTarget], + allNodes: Map[NodeId, Boolean /* isPolicyServer */ ], + groups: Map[NodeGroupId, Chunk[NodeId]] ): Chunk[NodeId] = { targets.foldLeft(Chunk[NodeId]()) { @@ -315,32 +318,19 @@ object RuleTarget extends Loggable { case AllTargetExceptPolicyServers => nodes ++ allNodes.collect { case (k, isPolicyServer) if (!isPolicyServer) => k } case AllPolicyServers => nodes ++ allNodes.collect { case (k, isPolicyServer) if (isPolicyServer) => k } case PolicyServerTarget(nodeId) => - if (allNodesAreThere) { - nodes :+ nodeId - } else { - // nodeId may not be in allNodes - // allNodes.keys.exists(x => x == nodeId) - Chunk.fromIterable(allNodes.keys).contains(nodeId) match { - case true => nodes :+ nodeId - case _ => nodes - } - } + nodes :+ nodeId // here, if we don't find the group, we consider it's an error in the // target recording, but don't fail, just log it. case GroupTarget(groupId) => val groupNodes = groups.getOrElse(groupId, Chunk.empty) val filtered = { - if (allNodesAreThere) groupNodes - else { - val keys = Chunk.fromIterable(allNodes.keys) - groupNodes.filter(keys.contains(_)) - } + groupNodes } nodes ++ filtered case TargetIntersection(targets) => - val nodeSets = targets.map(t => getNodeIdsChunkRec(Chunk(t), allNodes, groups, allNodesAreThere)) + val nodeSets = targets.map(t => getNodeIdsChunkRec(Chunk(t), allNodes, groups)) // Compute the intersection of the sets of Nodes val intersection = nodeSets.foldLeft(Chunk.fromIterable(allNodes.keys)) { case (currentIntersection, nodes) => currentIntersection.intersect(nodes) @@ -348,16 +338,16 @@ object RuleTarget extends Loggable { nodes ++ intersection case TargetUnion(targets) => - val nodeSets = targets.map(t => getNodeIdsChunkRec(Chunk(t), allNodes, groups, allNodesAreThere)) + val nodeSets = targets.map(t => getNodeIdsChunkRec(Chunk(t), allNodes, groups)) // Compute the union of the sets of Nodes val union = nodeSets.foldLeft(Chunk[NodeId]()) { case (currentUnion, nodes) => currentUnion.concat(nodes) } nodes ++ union case TargetExclusion(included, excluded) => // Compute the included Nodes - val includedNodes = getNodeIdsChunkRec(Chunk(included), allNodes, groups, allNodesAreThere) + val includedNodes = getNodeIdsChunkRec(Chunk(included), allNodes, groups) // Compute the excluded Nodes - val excludedNodes = getNodeIdsChunkRec(Chunk(excluded), allNodes, groups, allNodesAreThere) + val excludedNodes = getNodeIdsChunkRec(Chunk(excluded), allNodes, groups) // Remove excluded nodes from included nodes val result = includedNodes.filterNot(id => excludedNodes.contains(id)) nodes ++ result diff --git a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/NodeGroupRepository.scala b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/NodeGroupRepository.scala index 662edae58f6..b8b0c0bda85 100644 --- a/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/NodeGroupRepository.scala +++ b/webapp/sources/rudder/rudder-core/src/main/scala/com/normation/rudder/repository/NodeGroupRepository.scala @@ -353,7 +353,7 @@ object RoNodeGroupRepository { allNodeInfos: Map[NodeId, NodeInfo] ): Chunk[NodeId] = { val allNodes = allNodeInfos.view.mapValues(x => (x.isPolicyServer)) - RuleTarget.getNodeIdsChunk(targets, allNodes.toMap, allGroups, false) + RuleTarget.getNodeIdsChunk(targets, allNodes.toMap, allGroups) } }