Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
clarktsiory committed Dec 15, 2023
1 parent b44bb64 commit ca80d54
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,16 @@ import com.normation.rudder.domain.nodes.NodeGroupId
import com.normation.rudder.domain.policies.DirectiveId
import com.normation.rudder.domain.policies.PolicyMode
import com.normation.rudder.domain.policies.RuleId
import com.normation.rudder.domain.reports.ComplianceLevel
import com.normation.rudder.domain.reports._
import com.normation.rudder.domain.reports.ComplianceLevel
import com.normation.rudder.reports.ComplianceModeName
import java.lang
import net.liftweb.json._
import net.liftweb.json.JsonAST
import net.liftweb.json.JsonDSL._
import net.liftweb.json._
import org.apache.commons.csv.CSVFormat
import org.apache.commons.csv.QuoteMode

import java.lang

/**
* Here, we want to present two views of compliance:
* - by node
Expand Down Expand Up @@ -128,9 +127,8 @@ final case class ByNodeGroupCompliance(
name: String,
compliance: ComplianceLevel,
mode: ComplianceModeName,
rules: Seq[
ByRuleRuleCompliance
] // TODO: Several issues when using ByRuleRuleCompliance here : nodes > (rules) > directives etc. (rules is missing) AND 'all rules' all gotten (even though they have 0 'component')
rules: Seq[ByRuleRuleCompliance],
nodes: Seq[ByNodeNodeCompliance]
)

final case class ByRuleDirectiveCompliance(
Expand Down Expand Up @@ -789,72 +787,91 @@ object JsonCompliance {
~ ("compliance" -> nodeGroup.compliance.complianceWithoutPending(precision))
~ ("mode" -> nodeGroup.mode.name)
~ ("complianceDetails" -> percents(nodeGroup.compliance, precision))
~ ("rules" -> JArray(nodeGroup.rules.toList.map(_.toJson(level, precision))))
~ ("nodes" -> byNodes(nodeGroup.rules.flatMap(_.nodes), level, precision)))
~ ("rules" -> byRule(nodeGroup.rules, level, precision))
~ ("nodes" -> JArray(nodeGroup.nodes.map(_.toJson(level, precision)).toList)))
}

private[this] def byNodes(
nodes: Seq[GroupComponentCompliance],
// TODO: remove this method (or refactor and derive level)
private[this] def byRule(
rules: Seq[ByRuleRuleCompliance],
level: Int,
precision: CompliancePrecision
): Option[JsonAST.JValue] = {
if (level < 2) None
else {
Some(nodes.map { node =>
(
("id" -> node.id.value)
~ ("name" -> node.name)
~ ("compliance" -> node.compliance.complianceWithoutPending(precision))
~ ("complianceDetails" -> percents(node.compliance, precision))
~ ("directives" -> byNodesByDirectives(node.directives, level, precision))
)
Some(rules.map { rule =>
(("id" -> rule.id.serialize)
~ ("name" -> rule.name)
~ ("compliance" -> rule.compliance.complianceWithoutPending(precision))
~ ("mode" -> rule.mode.name)
~ ("complianceDetails" -> percents(rule.compliance, precision))
~ ("directives" -> directives(rule.directives, level, precision)))
})
}
}

private[this] def byNodesByDirectives(
directives: Seq[ByRuleByNodeByDirectiveCompliance],
private[this] def directives(
directives: Seq[ByRuleDirectiveCompliance],
level: Int,
precision: CompliancePrecision
): Option[JsonAST.JValue] = {
if (level < 3) None
if (level < 2) None
else {
Some(directives.map { directive =>
(
("id" -> directive.id.serialize)
~ ("name" -> directive.name)
~ ("compliance" -> directive.compliance.complianceWithoutPending(precision))
~ ("complianceDetails" -> percents(directive.compliance, precision))
~ ("components" -> byNodeByDirectiveByComponents(directive.components, level, precision))
~ ("components" -> components(directive.components, level, precision))
)
})
}
}

private[this] def byNodeByDirectiveByComponents(
comps: Seq[ByRuleByNodeByDirectiveByComponentCompliance],
private[this] def components(
comps: Seq[ByRuleComponentCompliance],
level: Int,
precision: CompliancePrecision
): Option[JsonAST.JValue] = {
if (level < 4) None
if (level < 3) None
else {
Some(comps.map { component =>
(
("name" -> component.name)
~ ("compliance" -> component.compliance.complianceWithoutPending(precision))
~ ("complianceDetails" -> percents(component.compliance, precision))
~ (component match {
case component: ByRuleByNodeByDirectiveByBlockCompliance =>
("components" -> byNodeByDirectiveByComponents(component.subComponents, level, precision))
case component: ByRuleByNodeByDirectiveByValueCompliance =>
("values" -> values(component.values, level))
case component: ByRuleBlockCompliance =>
("components" -> components(component.subComponents, level, precision))
case component: ByRuleValueCompliance =>
("nodes" -> nodes(component.nodes, level, precision))
})
)
})
}
}

def values(values: Seq[ComponentValueStatusReport], level: Int): Option[JsonAST.JValue] = {
private[this] def nodes(
nodes: Seq[ByRuleNodeCompliance],
level: Int,
precision: CompliancePrecision
): Option[JsonAST.JValue] = {
if (level < 4) None
else {
Some(nodes.map { node =>
(
("id" -> node.id.value)
~ ("name" -> node.name)
~ ("compliance" -> node.compliance.complianceWithoutPending(precision))
~ ("complianceDetails" -> percents(node.compliance, precision))
~ ("values" -> values(node.values, level))
)
})
}
}

private[this] def values(values: Seq[ComponentValueStatusReport], level: Int): Option[JsonAST.JValue] = {
if (level < 5) None
else {
Some(values.map { value =>
Expand All @@ -870,6 +887,7 @@ object JsonCompliance {
})
}
}

}

implicit class JsonByNodeCompliance(val n: ByNodeNodeCompliance) extends AnyVal {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -724,9 +724,13 @@ class ComplianceAPIService(
t2 <- currentTimeMillis
_ <- TimingDebugLoggerPure.trace(s"getByNodeGroupCompliance - nodeGroupRepo.getAllNodeIds in ${t2 - t1} ms")

directiveLib <- directiveRepo.getFullDirectiveLibrary()
t3 <- currentTimeMillis
_ <- TimingDebugLoggerPure.trace(s"getByNodeGroupCompliance - getFullDirectiveLibrary in ${t3 - t2} ms")

nodeInfos <- nodeInfoService.getAll()
t4 <- currentTimeMillis
_ <- TimingDebugLoggerPure.trace(s"getByNodeGroupCompliance - nodeInfoService.getAll() in ${t4 - t2} ms")
_ <- TimingDebugLoggerPure.trace(s"getByNodeGroupCompliance - nodeInfoService.getAll() in ${t4 - t3} ms")

compliance <- getGlobalComplianceMode().toIO
t5 <- currentTimeMillis
Expand Down Expand Up @@ -763,10 +767,40 @@ class ComplianceAPIService(
}) // TODO: make use of "allNodeAreThere argument"

// TODO: can we directly use 'rules reporting' to get compliances, or do we need filtering on 'nodes' which will be included ? Answer is maybe
// : YES for targeted compliance

byRuleCompliance <- getByRulesCompliance(globalRules, level)
// : YES for targeted compliance so we cannot simply "getByRulesCompliance"

byRuleCompliance <- getByRulesCompliance(globalRules, level) // TODO: we still get other rules than wanted ones here
reports <- reportingService
.findRuleNodeStatusReports(
nodeInfos.keySet,
globalRules.map(_.id).toSet
)
.toIO
} yield {
val ruleMap = globalRules.map(r => (r.id, r)).toMap
val byNodeCompliance = reports.toList.map {
case (nodeId, status) =>
ByNodeNodeCompliance(
nodeId,
nodeInfos.get(nodeId).map(_.hostname).getOrElse("Unknown node"),
ComplianceLevel.sum(status.reports.map(_.compliance)),
compliance.mode,
status.reports.toSeq.map(r => {
ByNodeRuleCompliance(
r.ruleId,
ruleMap.get(r.ruleId).map(_.name).getOrElse("Unknown rule"),
r.compliance,
r.directives.toSeq.map {
case (_, directiveReport) =>
ByNodeDirectiveCompliance(
directiveReport,
directiveLib.allDirectives.get(directiveReport.directiveId).map(_._2.name).getOrElse("Unknown Directive")
)
}
)
})
)
}
ByNodeGroupCompliance(
nodeGroup.id,
nodeGroup.name,
Expand All @@ -775,7 +809,8 @@ class ComplianceAPIService(
byRuleCompliance.map(_.compliance)
),
compliance.mode,
byRuleCompliance
byRuleCompliance,
byNodeCompliance
)
}
}
Expand Down

0 comments on commit ca80d54

Please sign in to comment.