Skip to content

Commit

Permalink
Fixes #22338: Refactor some code and changes API url for compliance b…
Browse files Browse the repository at this point in the history
…y directive

fixup! Fixes #22338: Refactor some code and changes API url for compliance by directive

Fixes #22338: Refactor some code and changes API url for compliance by directive
  • Loading branch information
ElaadF authored and VinceMacBuche committed Mar 7, 2023
1 parent 9e82281 commit e986730
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 98 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ trait StartsAtVersion13 extends EndpointSchema { val versions = ApiV.From(13) }
trait StartsAtVersion14 extends EndpointSchema { val versions = ApiV.From(14) }
trait StartsAtVersion15 extends EndpointSchema { val versions = ApiV.From(15) }
trait StartsAtVersion16 extends EndpointSchema { val versions = ApiV.From(16) }
trait StartsAtVersion17 extends EndpointSchema { val versions = ApiV.From(17) }

// utility extension trait to define the kind of API
trait PublicApi extends EndpointSchema { val kind = ApiKind.Public }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,27 +160,20 @@ object ComplianceApi extends ApiModuleProvider[ComplianceApi] {
val dataContainer = Some("globalCompliance")
}

final case object GetDirectiveComplianceId extends ComplianceApi with OneParam with StartsAtVersion10 with SortIndex {
final case object GetDirectiveComplianceId extends ComplianceApi with OneParam with StartsAtVersion17 with SortIndex {
val z = implicitly[Line].value
val description = "Get a directive's compliance"
val (action, path) = GET / "compliance" / "directives" / "{id}"
val dataContainer = Some("directiveCompliance")
}

final case object GetDirectivesCompliance extends ComplianceApi with ZeroParam with StartsAtVersion10 with SortIndex {
final case object GetDirectivesCompliance extends ComplianceApi with ZeroParam with StartsAtVersion17 with SortIndex {
val z = implicitly[Line].value
val description = "Get all directive's compliance"
val (action, path) = GET / "compliance" / "directives"
val dataContainer = Some("directivesCompliance")
}

final case object ExportDirectiveComplianceCSV extends ComplianceApi with OneParam with StartsAtVersion10 with SortIndex {
val z = implicitly[Line].value
val description = "Get a directive's compliance to CSV format"
val (action, path) = GET / "compliance" / "directives" / "export" / "{id}"
val dataContainer = Some("directiveComplianceExportCSV")
}

def endpoints = ca.mrvisser.sealerate.values[ComplianceApi].toList.sortBy(_.z)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1511,4 +1511,14 @@ final case class RestExtractorService(
}

}

def extractComplianceFormat(params: Map[String, List[String]]): Box[ComplianceFormat] = {
params.get("format") match {
case None | Some(Nil) | Some("" :: Nil) =>
Full(ComplianceFormat.JSON) // by default if no there is no format, should I choose the only one available ?
case Some(format :: _) =>
ComplianceFormat.fromValue(format).toBox
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ object AuthorizationApiMapping {
case Compliance.Read =>
ComplianceApi.GetGlobalCompliance.x :: ComplianceApi.GetRulesCompliance.x :: ComplianceApi.GetRulesComplianceId.x ::
ComplianceApi.GetNodesCompliance.x :: ComplianceApi.GetNodeComplianceId.x :: ChangesApi.GetRuleRepairedReports.x ::
ChangesApi.GetRecentChanges.x :: ComplianceApi.GetDirectiveComplianceId.x :: ComplianceApi.ExportDirectiveComplianceCSV.x ::
ChangesApi.GetRecentChanges.x :: ComplianceApi.GetDirectiveComplianceId.x ::
ComplianceApi.GetDirectivesCompliance.x :: Nil
case Compliance.Write => Nil
case Compliance.Edit => Nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -911,3 +911,22 @@ object JsonCompliance {
).filter { case (k, v) => v > 0 }.view.mapValues(percent => percent).toMap
}
}

sealed trait ComplianceFormat {
def value: String
}

object ComplianceFormat {
case object CSV extends ComplianceFormat { val value = "csv" }
case object JSON extends ComplianceFormat { val value = "json" }
def allValues = ca.mrvisser.sealerate.values[ComplianceFormat]
def fromValue(value: String): Either[String, ComplianceFormat] = {
allValues.find(_.value == value) match {
case None =>
Left(
s"Wrong type of value for compliance format '${value}', expected : ${allValues.map(_.value).mkString("[", ", ", "]")}"
)
case Some(action) => Right(action)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import com.normation.rudder.services.reports.ReportingService
import com.normation.zio.currentTimeMillis
import net.liftweb.common._
import net.liftweb.http.LiftResponse
import net.liftweb.http.PlainTextResponse
import net.liftweb.http.Req
import net.liftweb.json._
import net.liftweb.json.JsonDSL._
Expand Down Expand Up @@ -97,14 +98,13 @@ class ComplianceApi(
API.endpoints
.map(e => {
e match {
case API.GetRulesCompliance => GetRules
case API.GetRulesComplianceId => GetRuleId
case API.GetNodesCompliance => GetNodes
case API.GetNodeComplianceId => GetNodeId
case API.GetGlobalCompliance => GetGlobal
case API.GetDirectiveComplianceId => GetDirectiveId
case API.GetDirectivesCompliance => GetDirectives
case API.ExportDirectiveComplianceCSV => ExportCSV
case API.GetRulesCompliance => GetRules
case API.GetRulesComplianceId => GetRuleId
case API.GetNodesCompliance => GetNodes
case API.GetNodeComplianceId => GetNodeId
case API.GetGlobalCompliance => GetGlobal
case API.GetDirectiveComplianceId => GetDirectiveId
case API.GetDirectivesCompliance => GetDirectives
}
})
.toList
Expand Down Expand Up @@ -194,45 +194,6 @@ class ComplianceApi(
}
}

object ExportCSV extends LiftApiModule {
val schema = API.ExportDirectiveComplianceCSV
val restExtractor = restExtractorService
def process(
version: ApiVersion,
path: ApiPath,
directiveId: String,
req: Req,
params: DefaultParams,
authzToken: AuthzToken
): LiftResponse = {
implicit val action = schema.name
implicit val prettify = params.prettify

(for {
level <- restExtractor.extractComplianceLevel(req.params)
t1 = System.currentTimeMillis
precision <- restExtractor.extractPercentPrecision(req.params)
id <- DirectiveId.parse(directiveId).toBox
t2 = System.currentTimeMillis

directive <- complianceService.getDirectiveCompliance(id, level)
t3 = System.currentTimeMillis
_ = TimingDebugLogger.trace(s"API Export compliance to CSV - getting query param in ${t2 - t1} ms")
_ = TimingDebugLogger.trace(s"API Export compliance to CSV - getting directive compliance in ${t3 - t2} ms")

} yield {
directive.toCsv
}) match {
case Full(csv) =>
toJsonResponse(None, ("directiveComplianceExportCSV" -> csv.mkString("\n")))

case eb: EmptyBox =>
val message = (eb ?~ (s"Could not export to CSV compliance for directive '${directiveId}'")).messageChain
toJsonError(None, JString(message))
}
}
}

object GetDirectiveId extends LiftApiModule {
val schema = API.GetDirectiveComplianceId
val restExtractor = restExtractorService
Expand All @@ -246,35 +207,32 @@ class ComplianceApi(
): LiftResponse = {
implicit val action = schema.name
implicit val prettify = params.prettify

(for {
level <- restExtractor.extractComplianceLevel(req.params)
t1 = System.currentTimeMillis
precision <- restExtractor.extractPercentPrecision(req.params)
format <- restExtractorService.extractComplianceFormat(req.params)
id <- DirectiveId.parse(directiveId).toBox
t2 = System.currentTimeMillis

_ = TimingDebugLogger.trace(s"API DirectiveCompliance - getting query param in ${t2 - t1} ms")
directive <- complianceService.getDirectiveCompliance(id, level)
t3 = System.currentTimeMillis
_ = TimingDebugLogger.trace(s"API GetDirectiveId - getting query param in ${t2 - t1} ms")
_ = TimingDebugLogger.trace(s"API GetDirectiveId - getting directive compliance in ${t3 - t2} ms")

_ = TimingDebugLogger.trace(s"API DirectiveCompliance - getting directive compliance '${id.uid.value}' in ${t3 - t2} ms")
} yield {
if (version.value <= 6) {
directive.toJsonV6
} else {
val json = directive.toJson(
level.getOrElse(10),
precision.getOrElse(CompliancePrecision.Level2)
) // by default, all details are displayed
val t4 = System.currentTimeMillis
TimingDebugLogger.trace(s"API GetDirectiveId - serialize to json in ${t4 - t3} ms")
json
format match {
case ComplianceFormat.CSV =>
PlainTextResponse(directive.toCsv.mkString("\n"))
case ComplianceFormat.JSON =>
val json = directive.toJson(
level.getOrElse(10),
precision.getOrElse(CompliancePrecision.Level2)
) // by default, all details are displayed
val t4 = System.currentTimeMillis
TimingDebugLogger.trace(s"API DirectiveCompliance - serialize to json in ${t4 - t3} ms")
toJsonResponse(None, ("directiveCompliance" -> json))
}
}) match {
case Full(rule) =>
toJsonResponse(None, ("directiveCompliance" -> rule))

case Full(compliance) => compliance
case eb: EmptyBox =>
val message = (eb ?~ (s"Could not get compliance for directive '${directiveId}'")).messageChain
toJsonError(None, JString(message))
Expand All @@ -300,30 +258,26 @@ class ComplianceApi(
t1 = System.currentTimeMillis
precision <- restExtractor.extractPercentPrecision(req.params)
t2 = System.currentTimeMillis
_ = TimingDebugLogger.trace(s"API DirectivesCompliance - getting query param in ${t2 - t1} ms")
fullLibrary <- readDirective.getFullDirectiveLibrary().toBox ?~! "Could not fetch Directives"
t3 = System.currentTimeMillis
directiveIds = fullLibrary.allDirectives.values.filter(!_._2.isSystem).map(_._2.id).toList
// id <- DirectiveId.parse(directiveId).toBox
t3 = System.currentTimeMillis
_ = TimingDebugLogger.trace(s"API DirectivesCompliance - getting directives id ${t3 - t2} ms")
t4 = System.currentTimeMillis
directives = directiveIds.flatMap(complianceService.getDirectiveCompliance(_, level))
t5 = System.currentTimeMillis
_ = TimingDebugLogger.trace(s"API GetDirectives - getting query param in ${t2 - t1} ms")
_ = TimingDebugLogger.trace(s"API GetDirectives - getting directive compliance in ${t3 - t2} ms")
_ = TimingDebugLogger.trace(s"API DirectivesCompliance - getting directives compliance in ${t5 - t4} ms")

} yield {
if (version.value <= 6) {
directives.map(_.toJsonV6)
} else {
val json = directives.map(
_.toJson(
level.getOrElse(10),
precision.getOrElse(CompliancePrecision.Level2)
)
) // by default, all details are displayed
val t4 = System.currentTimeMillis
TimingDebugLogger.trace(s"API GetDirectiveId - serialize to json in ${t4 - t3} ms")
json
}
val json = directives.map(
_.toJson(
level.getOrElse(10),
precision.getOrElse(CompliancePrecision.Level2)
)
) // by default, all details are displayed
val t6 = System.currentTimeMillis
TimingDebugLogger.trace(s"API DirectivesCompliance - serialize to json in ${t6 - t5} ms")
json
}) match {
case Full(rule) =>
toJsonResponse(None, ("directivesCompliance" -> rule))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,9 @@ getCSVExport model =
request
{ method = "GET"
, headers = []
, url = getUrl model [ "compliance", "directives", "export", model.directiveId.value ] []
, url = getUrl model [ "compliance", "directives", model.directiveId.value ] [ Url.Builder.string "format" "csv"]
, body = emptyBody
, expect = expectJson Export decodeExportCVS
, expect = expectString Export
, timeout = Nothing
, tracker = Nothing
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ decodeGetDirectiveCompliance : Decoder DirectiveCompliance
decodeGetDirectiveCompliance =
at ["data", "directiveCompliance" ] decodeDirectiveCompliance

decodeExportCVS : Decoder String
decodeExportCVS =
at ["data", "directiveComplianceExportCSV"] string

decodeDirectiveCompliance : Decoder DirectiveCompliance
decodeDirectiveCompliance =
succeed DirectiveCompliance
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1686,6 +1686,7 @@ object RudderConfig extends Loggable {
ApiVersion(14, false) :: // rudder 7.0
ApiVersion(15, false) :: // rudder 7.1 - system update on node details
ApiVersion(16, false) :: // rudder 7.2 - create node api, import/export archive, hooks & campaigns internal API
ApiVersion(17, false) :: // rudder 7.3 - directive compliance API
Nil
}

Expand Down

0 comments on commit e986730

Please sign in to comment.