Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
fanf committed Aug 9, 2017
1 parent ed1c6ef commit 0f0b554
Show file tree
Hide file tree
Showing 4 changed files with 157 additions and 18 deletions.
@@ -0,0 +1,33 @@
#!/bin/sh

# Hooks parameter are passed by environment variable:
#

# - RUDDER_REPORT_SEVERITY : report severity level (result_error, result_repaired, audit_noncompliant, audit_error, log_warn)
# - RUDDER_REPORT_EXECUTION_DATETIME : date/time (ISO-8601 YYYY-MM-ddTHH:mm:ss.sssZ) when log was writen (node local time)
# - RUDDER_REPORT_RUN_DATETIME : date/time (ISO-8601 YYYY-MM-ddTHH:mm:ss.sssZ) when run for that log started
# - RUDDER_NODE_ID : nodeId
# - RUDDER_NODE_HOSTNAME : node fully qualified hostname
# - RUDDER_REPORT_RULE_ID : rule ID of report
# - RUDDER_REPORT_RULE_NAME : rule human readable name of report
# - RUDDER_REPORT_DIRECTIVE_ID : directive ID of report
# - RUDDER_REPORT_DIRECTIVE_NAME : directive human readable name of report
# - RUDDER_REPORT_TECHNIQUE_ID : technique ID from which the directive is derived
# - RUDDER_REPORT_TECHNIQUE_VERSION : technique version from which the directive is derived
# - RUDDER_REPORT_COMPONENT_NAME : component name (i.e key) in the directive for that report
# - RUDDER_REPORT_COMPONENT_VALUE : component value bound to the component name
# - RUDDER_REPORT_MESSAGE : report message

# Errors code on hooks are interpreted as follow:
# - 0 : success, no log (appart if debug one) , continue to next hook
# - 1-31 : error , error log in /var/log/rudder/webapp/, stop processing
# - 32-63 : warning, warning log in /var/log/rudder/webapp/, continue to next hook
# - 64-255: reserved for futur use case. Behavior may change without notice.

#
# Be careful with non-compliant reports hooks. The may impact the performance of the system if
# non-compliant report rate is hight. These hooks should be make to be the most efficient
# possible and should execute asynchronuously.
#

exit 0
@@ -0,0 +1,33 @@
= node-post-acceptance

== When/What ?

This directory contains hooks executed after a node was successfully accepted.

Typically, these hooks triggers action on other system, like registering the node
into a monitoring system or into an external CMDB, or to send notification.

Be careful with non-compliant reports hooks. The may impact the performance of the system if
non-compliant report rate is hight. These hooks should be make to be the most efficient
possible and should execute asynchronuously.


== Parameters

Hooks parameters are passed by environment variable:

- RUDDER_REPORT_SEVERITY : report severity level (result_error, result_repaired, audit_noncompliant, audit_error, log_warn)
- RUDDER_REPORT_EXECUTION_DATETIME : date/time (ISO-8601 YYYY-MM-ddTHH:mm:ss.sssZ) when log was writen (node local time)
- RUDDER_REPORT_RUN_DATETIME : date/time (ISO-8601 YYYY-MM-ddTHH:mm:ss.sssZ) when run for that log started
- RUDDER_NODE_ID : nodeId
- RUDDER_NODE_HOSTNAME : node fully qualified hostname
- RUDDER_REPORT_RULE_ID : rule ID of report
- RUDDER_REPORT_RULE_NAME : rule human readable name of report
- RUDDER_REPORT_DIRECTIVE_ID : directive ID of report
- RUDDER_REPORT_DIRECTIVE_NAME : directive human readable name of report
- RUDDER_REPORT_TECHNIQUE_ID : technique ID from which the directive is derived
- RUDDER_REPORT_TECHNIQUE_VERSION : technique version from which the directive is derived
- RUDDER_REPORT_COMPONENT_NAME : component name (i.e key) in the directive for that report
- RUDDER_REPORT_COMPONENT_VALUE : component value bound to the component name
- RUDDER_REPORT_MESSAGE : report message

Expand Up @@ -54,6 +54,10 @@ import net.liftweb.actor._
import net.liftweb.common._
import scala.concurrent.Await
import scala.concurrent.duration.Duration
import com.normation.rudder.domain.logger.ReportLoggerLevel
import com.normation.rudder.hooks.HookEnvPairs
import com.normation.rudder.hooks.RunHooks
import com.normation.rudder.hooks.Hooks

/**
* This object will be used as message for the non compliant reports logger
Expand All @@ -67,12 +71,14 @@ object StartAutomaticReporting
* Informations of logs a are taken from different repository
*/
class AutomaticReportLogger(
propertyRepository : RudderPropertiesRepository
, reportsRepository : ReportsRepository
, ruleRepository : RoRuleRepository
, directiveRepository : RoDirectiveRepository
, nodeInfoService : NodeInfoService
, reportLogInterval : Int
propertyRepository : RudderPropertiesRepository
, reportsRepository : ReportsRepository
, ruleRepository : RoRuleRepository
, directiveRepository : RoDirectiveRepository
, nodeInfoService : NodeInfoService
, reportLogInterval : Int
, HOOKS_D : String
, HOOKS_IGNORE_SUFFIXES: List[String]
) extends Loggable {

private val propertyName = "rudder.batch.reports.logInterval"
Expand Down Expand Up @@ -113,6 +119,7 @@ class AutomaticReportLogger(
nodes <- nodeInfoService.getAll
rules <- ruleRepository.getAll(true)
directives <- directiveRepository.getFullDirectiveLibrary()
hooks <- nonCompliantReportHooks
} yield {
val id = hundredReports.headOption match {
// None means this is a new rudder without any reports, don't log anything, current id is 0
Expand All @@ -122,7 +129,7 @@ class AutomaticReportLogger(

// return last id and report the latest 100 non compliant reports
case Some(report) =>
logReports(hundredReports.reverse, nodes, rules.map(r => (r.id, r)).toMap, directives)
logReports(hundredReports.reverse, nodes, rules.map(r => (r.id, r)).toMap, directives, hooks)
report._1
}
updateLastId(id)
Expand Down Expand Up @@ -181,10 +188,11 @@ class AutomaticReportLogger(
): Box[Long] = {
for {
reports <- reportsRepository.getReportsByKindBeetween(fromId, maxId, batchSize, reportsKind)
hooks <- nonCompliantReportHooks
} yield {
//when we get an empty here, it means that we don't have more non-compliant report
//in the interval, just return the max id
val id = logReports(reports, allNodes, rules, directives).getOrElse(maxId)
val id = logReports(reports, allNodes, rules, directives, hooks).getOrElse(maxId)
logger.debug(s"Wrote non-compliant-reports logs from id '${fromId}' to id '${id}'")
updateLastId(id)
id
Expand Down Expand Up @@ -246,10 +254,19 @@ class AutomaticReportLogger(
maxTry(0)
}

def logReports(reports : Seq[(Long, Reports)], allNodes: Map[NodeId, NodeInfo], rules: Map[RuleId, Rule], directives: FullActiveTechniqueCategory): Option[Long] = {
private[this] def nonCompliantReportHooks = RunHooks.getHooks(HOOKS_D + "/non-compliant-report", HOOKS_IGNORE_SUFFIXES)

def logReports(reports : Seq[(Long, Reports)], allNodes: Map[NodeId, NodeInfo], rules: Map[RuleId, Rule], directives: FullActiveTechniqueCategory, hooks: Hooks): Option[Long] = {
if(reports.isEmpty) {
None
} else {
// avoid to get environment variable and hooks for each line, its costly
val systemEnv = {
import scala.collection.JavaConverters._
HookEnvPairs.build(System.getenv.asScala.toSeq:_*)
}

// log all non-compliant reports for that batch (+hooks)
val loggedIds = reports.map { case (id, report) =>
val t = report.executionDate.toString("yyyy-MM-dd HH:mm:ssZ")
val s = report.severity
Expand All @@ -266,10 +283,43 @@ class AutomaticReportLogger(
val v = report.keyValue
val m = report.message


val reportLogger = AllReportLogger.findLogger(report.severity)

//exceptionnally use $var in place of ${var} for log format lisibility
val reportLine = s"[$t] N: $nid [$n] S: [$s] R: $rid [$r] D: $did [$d] T: $tn/$tv C: [$c] V: [$v] $m"

AllReportLogger.FindLogger(report.severity)(reportLine)
reportLogger.log(reportLine)

// hooks only for non compliant
reportLogger match {
case AllReportLogger.ReportLoggerLevel.Info => //nothing
case AllReportLogger.ReportLoggerLevel.Error |
AllReportLogger.ReportLoggerLevel.Warn =>

// hooks
val hookEnv = HookEnvPairs.build(
("RUDDER_REPORT_SEVERITY" , s)
, ("RUDDER_REPORT_EXECUTION_DATETIME" , t)
, ("RUDDER_REPORT_RUN_DATETIME" , report.executionTimestamp.toString("yyyy-MM-dd HH:mm:ssZ"))
, ("RUDDER_REPORT_NODE_ID" , nid)
, ("RUDDER_REPORT_NODE_HOSTNAME" , n)
, ("RUDDER_REPORT_RULE_ID" , rid)
, ("RUDDER_REPORT_RULE_NAME" , r)
, ("RUDDER_REPORT_DIRECTIVE_ID" , did)
, ("RUDDER_REPORT_DIRECTIVE_NAME" , d)
, ("RUDDER_REPORT_TECHNIQUE_ID" , tn.toString)
, ("RUDDER_REPORT_TECHNIQUE_VERSION" , tv)
, ("RUDDER_REPORT_COMPONENT_NAME" , c)
, ("RUDDER_REPORT_COMPONENT_VALUE" , v)
, ("RUDDER_REPORT_MESSAGE" , m)
)

val startHooks = System.currentTimeMillis
RunHooks.syncRun(hooks, hookEnv, systemEnv)
val timeHooks = (System.currentTimeMillis - startHooks)
logger.debug(s"Non-compliance scripts hooks ran in ${timeHooks} ms")
}

id
}
Expand Down
Expand Up @@ -45,25 +45,48 @@ object ReportLogger extends Logger {
override protected def _logger = LoggerFactory.getLogger("report")
}

/**
* A data structure for our Report Level
*/
sealed trait ReportLoggerLevel {
def log: (=> AnyRef) => Unit
}


object AllReportLogger extends Logger {
override protected def _logger = LoggerFactory.getLogger("non-compliant-reports")

def FindLogger(reportType : String) :((=> AnyRef) => Unit) = {
final object ReportLoggerLevel {

final case object Error extends ReportLoggerLevel {
override def log = error
}

final case object Warn extends ReportLoggerLevel {
override def log = info
}

final case object Info extends ReportLoggerLevel {
override def log = info
}

}

def findLogger(reportType : String): ReportLoggerLevel = {
import Reports._

reportType match{
// error
case RESULT_ERROR => error
case AUDIT_NONCOMPLIANT => error
case AUDIT_ERROR => error
case RESULT_ERROR => ReportLoggerLevel.Error
case AUDIT_NONCOMPLIANT => ReportLoggerLevel.Error
case AUDIT_ERROR => ReportLoggerLevel.Error

// warning
case RESULT_REPAIRED => warn
case LOG_WARN => warn
case LOG_WARNING => warn
case RESULT_REPAIRED => ReportLoggerLevel.Warn
case LOG_WARN => ReportLoggerLevel.Warn
case LOG_WARNING => ReportLoggerLevel.Warn

case _ => info
case _ => ReportLoggerLevel.Info
}
}
}
Expand Down

0 comments on commit 0f0b554

Please sign in to comment.