Skip to content

Commit

Permalink
Fixes #19323: Be able to group reporting and methods so that we have …
Browse files Browse the repository at this point in the history
…clearer techniques and a better reporting
  • Loading branch information
VinceMacBuche committed May 27, 2021
1 parent 8e665e5 commit bb47760
Show file tree
Hide file tree
Showing 35 changed files with 2,359 additions and 987 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ package com.normation.cfclerk.domain
import cats.implicits._
import com.normation.cfclerk.xmlparsers.CfclerkXmlConstants._
import com.normation.cfclerk.xmlparsers.EmptyReportKeysValue
import com.normation.errors.IOResult
import com.normation.errors.Unexpected

/**
* This file define the model for metadata of object
Expand Down Expand Up @@ -100,6 +102,7 @@ final case class SectionSpec(
, displayPriority : DisplayPriority = HighDisplayPriority
, description : String = ""
, children : Seq[SectionChildSpec] = Seq()
, compositionRule: Option[CompositionRule ] = None
) extends SectionChildSpec {

lazy val getDirectVariables : Seq[VariableSpec] = {
Expand Down Expand Up @@ -136,10 +139,6 @@ final case class SectionSpec(
private def recCloneMultivalued: Either[LoadTechniqueError, SectionSpec] = {
val multivaluedChildren = children.toList.traverse { child => child match {
case s: SectionSpec =>
if (s.isMultivalued) LoadTechniqueError.Consistancy(
"A multivalued section should not contain other multivalued sections." +
" It may contain only imbricated sections or variables.").invalidNel
else
s.recCloneMultivalued.toValidatedNel
case v: SectionVariableSpec => v.cloneSetMultivalued.validNel
} }.leftMap(errs => LoadTechniqueError.Accumulated(errs)).toEither
Expand Down Expand Up @@ -437,3 +436,20 @@ object DisplayPriority {
}
}
}

sealed trait CompositionRule
case object WorstReport extends CompositionRule
case object SumReport extends CompositionRule
case class ComponentReport(component : String) extends CompositionRule

object CompositionRule {
import zio.syntax._
def apply(value : String) : IOResult[CompositionRule] = {
value match {
case "worst" => WorstReport.succeed
case "sum" => SumReport.succeed
case s"component:${a}" => ComponentReport(a).succeed
case _ => Unexpected(s"Value '${value}' is not a valid reporting composition rule.").fail
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,11 @@ class SectionSpecParser(variableParser:VariableSpecParser) extends Loggable {
case null | Some("") => None
case x => x
}

import com.normation.box.IOToBox
val composition = (root \ ("@composition")).headOption.map( _.text) match {
case null | Some("") | None => None
case Some(x) => CompositionRule(x).toBox.toOption
}
// Checking if we have predefined values
for {
name <- optName
Expand Down Expand Up @@ -190,10 +194,10 @@ class SectionSpecParser(variableParser:VariableSpecParser) extends Loggable {
/**
* A key must be define if and only if we are in a multivalued, component section.
*/
_ <- if(isMultivalued && isComponent && effectiveComponentKey.isEmpty) {
_ <- if(isMultivalued && isComponent && effectiveComponentKey.isEmpty && composition.isEmpty) {
Left(LoadTechniqueError.Parsing("Section '%s' is multivalued and is component. A componentKey attribute must be specified".format(name)))
} else Right("ok")
sectionSpec = SectionSpec(name, isMultivalued, isComponent, effectiveComponentKey, displayPriority, description, children)
sectionSpec = SectionSpec(name, isMultivalued, isComponent, effectiveComponentKey, displayPriority, description, children, composition)
res <- if (isMultivalued) sectionSpec.cloneVariablesInMultivalued
else Right(sectionSpec)
} yield {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,11 @@

package com.normation.rudder.domain.reports

import com.normation.cfclerk.domain.ComponentReport
import com.normation.cfclerk.domain.CompositionRule
import com.normation.cfclerk.domain.SumReport
import com.normation.cfclerk.domain.TechniqueVersion
import com.normation.cfclerk.domain.WorstReport
import com.normation.inventory.domain.NodeId
import com.normation.rudder.domain.policies.DirectiveId
import com.normation.rudder.domain.policies.PolicyMode
Expand Down Expand Up @@ -130,14 +134,24 @@ final case class DirectiveExpectedReports (
/**
* The Cardinality is per Component
*/
final case class ComponentExpectedReport(
trait ComponentExpectedReport {
def componentName : String
}

final case class GroupComponentExpectedReport (
componentName : String
, compositionRule : CompositionRule
, subComponents : List[ComponentExpectedReport]
) extends ComponentExpectedReport

final case class UniqueComponentExpectedReport(
componentName : String

//TODO: change that to have a Seq[(String, String).
//or even better, un Seq[ExpectedValue] where expectedValue is the pair
, componentsValues : List[String]
, unexpandedComponentsValues: List[String]
) {
) extends ComponentExpectedReport {

/**
* Get a normalized list of pair of (value, unexpandedvalue).
Expand Down Expand Up @@ -246,25 +260,38 @@ object ExpectedReportsSerialisation {
)
}

def jsonComponentExpectedReport(c : ComponentExpectedReport): JValue = {

c match {
case c: UniqueComponentExpectedReport =>
(("componentName" -> c.componentName)
~ ("values" -> c.componentsValues)
~ ("unexpanded" -> c.unexpandedComponentsValues)
)
case c: GroupComponentExpectedReport =>
(("componentName" -> c.componentName)
~ ("composition" -> (c.compositionRule match {
case WorstReport => "worst"
case SumReport => "sum"
case ComponentReport(component) => s"component:${component}"
}))
~ ("subComponents" -> c.subComponents.map(jsonComponentExpectedReport))
)
}
}
def jsonRuleExpectedReports(rules: List[RuleExpectedReports]): JArray = {
(
rules.map { r =>
(
("ruleId" -> r.ruleId.value)
~ ("directives" -> (r.directives.map { d =>
~ ("directives" -> r.directives.map { d =>
(
("directiveId" -> d.directiveId.value)
~ ("policyMode" -> d.policyMode.map( _.name))
~ ("isSystem" -> d.isSystem )
~ ("components" -> (d.components.map { c =>
(
("componentName" -> c.componentName)
~ ("values" -> c.componentsValues)
~ ("unexpanded" -> c.unexpandedComponentsValues)
)
}))
~ ("components" -> d.components.map(jsonComponentExpectedReport))
)
}))
})
)
}
)
Expand Down Expand Up @@ -403,7 +430,11 @@ object ExpectedReportsSerialisation {
case _ => false
}

DirectiveExpectedReports(DirectiveId(id), policyMode(jsonMode), isSystem, components.toList)
println("palmashow")
println(components)
val res = DirectiveExpectedReports(DirectiveId(id), policyMode(jsonMode), isSystem, components.toList)
println(res)
res
}
case _ =>
Failure(s"Error when parsing directive expected reports from json: '${compactRender(json)}'")
Expand All @@ -417,9 +448,22 @@ object ExpectedReportsSerialisation {
// , (json \ "cardinality") // #10625: ignore cardinality
, (json \ "values").extractOpt[List[String]]
, (json \ "unexpanded").extractOpt[List[String]]
, (json \ "subComponents") match {
case JArray(subs) => Some(com.normation.utils.Control.sequence(subs)(component))
case _=> None
}

, (json \ "composition").extractOpt[String]
) match {
case (JString(name), Some(values), Some(unexpanded) ) =>
tryo(ComponentExpectedReport(name, values, unexpanded))
case (JString(name), Some(values), Some(unexpanded), None, None ) =>
Full(UniqueComponentExpectedReport(name, values, unexpanded))
case (JString(name), _, _, Some(Full(sub)), Some(composition) )=>
import com.normation.box.IOToBox
for {
compositionRule <- CompositionRule(composition).toBox
} yield {
GroupComponentExpectedReport(name, compositionRule, sub.toList)
}
case _ =>
Failure(s"Error when parsing component expected reports from json: '${compactRender(json)}'")
}
Expand Down
Loading

0 comments on commit bb47760

Please sign in to comment.