Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #15713: Show log informations next to reports and full compliance report #2501

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -84,11 +84,16 @@ trait ReportsRepository {
) : Seq[Reports]

def findReportsByNodeOnInterval(
nodeId: NodeId
nodeId: NodeId
, start : DateTime
, end : DateTime
) : Seq[Reports]

def findReportsByNodeByRun(
nodeId: NodeId
, runDate : DateTime
) : Seq[Reports]

//databaseManager only
def getReportsInterval() : Box[(Option[DateTime], Option[DateTime])]
def getArchivedReportsInterval() : Box[(Option[DateTime], Option[DateTime])]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,17 @@ class ReportsJdbcRepository(doobie: Doobie) extends ReportsRepository with Logga
transactRun(xa => q.to[Vector].transact(xa))
}


override def findReportsByNodeByRun(
nodeId: NodeId
, runDate : DateTime
) : Vector[Reports] = {
val q = Query[(NodeId, DateTime), Reports](baseQuery +
" and nodeId = ? and executionTimeStamp = ? ORDER BY executionTimeStamp asc"
, None).toQuery0((nodeId, runDate))
transactRun(xa => q.to[Vector].transact(xa))
}

override def findReportsByNodeOnInterval(
nodeId: NodeId
, start : DateTime
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2016,6 +2016,7 @@ object RudderConfig extends Loggable {
, reportingServiceImpl
, techniqueRepositoryImpl
, configService
, logDisplayerImpl
)
private[this] lazy val propertyRepository = new RudderPropertiesRepositoryImpl(doobie)
private[this] lazy val autoReportLogger = new AutomaticReportLogger(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ class ShowNodeDetailsFromNode(
"#nodeDetails" #> DisplayNode.showNodeDetails(inventory, Some((node, globalMode)), Some(node.creationDate), AcceptedInventory, isDisplayingInPopup = withinPopup) &
"#nodeInventory *" #> DisplayNode.show(inventory, false) &
"#reportsDetails *" #> reportDisplayer.asyncDisplay(node) &
"#logsDetails *" #> logDisplayer.asyncDisplay(node.id) &
"#logsDetails *" #> Script(OnLoad(logDisplayer.asyncDisplay(node.id,None, "logsGrid"))) &
"#node_parameters -*" #> (if(node.id == Constants.ROOT_POLICY_SERVER_ID) NodeSeq.Empty else nodeStateEditForm(node).nodeStateConfiguration) &
"#node_parameters -*" #> agentPolicyModeEditForm.cfagentPolicyModeConfiguration &
"#node_parameters -*" #> agentScheduleEditForm(node).cfagentScheduleConfiguration &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,9 @@ class EventListDisplayer( repos : EventLogRepository
val refresh = AnonFunc(SHtml.ajaxInvoke( () => getLastEvents))

Script(OnLoad(JsRaw(s"""
var pickEventLogsInInterval = ${AnonFunc(SHtml.ajaxCall(JsRaw(
"""'{"start":"'+$(".pickStartInput").val()+'", "end":"'+$(".pickEndInput").val()+'"}'"""
), getEventsInterval)._2).toJsCmd}
var refreshEventLogs = ${refresh.toJsCmd};
createEventLogTable('${gridName}',[], '${S.contextPath}', refreshEventLogs, pickEventLogsInInterval)
initDatePickers("#filterLogs", ${AnonFunc("param", SHtml.ajaxCall(JsVar("param"), getEventsInterval)._2).toJsCmd});
createEventLogTable('${gridName}',[], '${S.contextPath}', refreshEventLogs)
refreshEventLogs();
""")))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,12 @@ import com.normation.rudder.domain.policies.RuleId
import com.normation.rudder.web.model._
import com.normation.inventory.domain.NodeId
import com.normation.rudder.domain.reports.Reports
import scala.xml._
import net.liftweb.common._
import net.liftweb.http._
import net.liftweb.http.js._
import JsCmds._
import JE._

import scala.collection._
import com.normation.rudder.domain.policies.DirectiveId
import com.normation.rudder.repository.ReportsRepository
Expand All @@ -57,8 +57,8 @@ import com.normation.cfclerk.xmlparsers.CfclerkXmlConstants.DEFAULT_COMPONENT_KE
import net.liftweb.json.JsonAST.JString
import org.joda.time.format.DateTimeFormat
import com.normation.rudder.web.ChooseTemplate

import com.normation.box._
import com.normation.rudder.web.components.DateFormaterService

/**
* Show the reports from cfengine (raw data)
Expand All @@ -74,12 +74,15 @@ class LogDisplayer(
, "logs-content"
)

private val gridName = "logsGrid"

def asyncDisplay(nodeId : NodeId) : NodeSeq = {
def ajaxRefresh(nodeId : NodeId, runDate : Option[DateTime], tableId : String) = {
runDate match {
case Some(runDate) => SHtml.ajaxInvoke(() => refreshData(nodeId, reportRepository.findReportsByNodeByRun(nodeId, runDate).filter(_.severity.startsWith("log")), tableId))
case None => SHtml.ajaxInvoke(() => refreshData(nodeId, reportRepository.findReportsByNode(nodeId), tableId))
}
}
def asyncDisplay(nodeId : NodeId, runDate : Option[DateTime], tableId :String) = {
val id = JsNodeId(nodeId)
val ajaxRefresh = SHtml.ajaxInvoke( () => refreshData(nodeId, reportRepository.findReportsByNode(nodeId)))

val refresh = ajaxRefresh(nodeId,runDate, tableId)
def getEventsInterval(jsonInterval: String): JsCmd = {
import net.liftweb.util.Helpers.tryo
import net.liftweb.json.parse
Expand All @@ -104,7 +107,7 @@ class LogDisplayer(
}
}) match {
case Full(reports) =>
refreshData(nodeId, reports)
refreshData(nodeId, reports, tableId)
case eb : EmptyBox =>
val fail = eb ?~! "Could not get latest event logs"
logger.error(fail.messageChain)
Expand All @@ -113,28 +116,26 @@ class LogDisplayer(
}
}

Script(
OnLoad(
// set static content
SetHtml("logsDetails",content) &
// Create empty table
JsRaw(s"""
var pickEventLogsInInterval = ${AnonFunc(SHtml.ajaxCall(JsRaw(
"""'{"start":"'+$(".pickStartInput").val()+'", "end":"'+$(".pickEndInput").val()+'"}'"""
), getEventsInterval)._2).toJsCmd}

createTechnicalLogsTable("${gridName}",[], "${S.contextPath}",function() {${ajaxRefresh.toJsCmd}}, pickEventLogsInInterval);""") &
// Load data asynchronously

JsRaw(
s"""
$$("#details_${id}").on( "tabsactivate", function(event, ui) {
( if (runDate.isEmpty) {
// set static content
SetHtml("logsDetails", content)
} else {
Noop
} ) &
// Create empty table
JsRaw(s"""
${if (runDate.isEmpty) {
s"""$$("#details_${id}").on( "tabsactivate", function(event, ui) {
if(ui.newPanel.attr('id')== 'node_logs') {
${ajaxRefresh.toJsCmd}
${refresh.toJsCmd}
}
});
initDatePickers("#filterLogs", ${AnonFunc("param",SHtml.ajaxCall(JsVar("param"), getEventsInterval)._2).toJsCmd});
"""} else ""
}
createTechnicalLogsTable("${tableId}",[], "${S.contextPath}",function() {${refresh.toJsCmd}}, ${runDate.isEmpty});
"""
)))
)
}

/**
Expand Down Expand Up @@ -169,6 +170,7 @@ class LogDisplayer(

ReportLine (
report.executionDate
, report.executionTimestamp
, report.severity
, ruleName
, directiveName
Expand All @@ -183,11 +185,11 @@ class LogDisplayer(

}

def refreshData(nodeId : NodeId, reports: => Seq[Reports]) : JsCmd = {
def refreshData(nodeId : NodeId, reports: => Seq[Reports], tableId : String) : JsCmd = {

val data = getReportsLineForNode(nodeId, reports).json.toJsCmd

OnLoad(JsRaw(s"""refreshTable("${gridName}",${data});""")
OnLoad(JsRaw(s"""refreshTable("${tableId}",${data});""")
)
}
}
Expand All @@ -205,6 +207,7 @@ class LogDisplayer(
*/
case class ReportLine (
executionDate : DateTime
, runDate : DateTime
, severity : String
, ruleName : String
, directiveName : String
Expand All @@ -216,7 +219,8 @@ case class ReportLine (
override val json = {

JsObj(
( "executionDate", executionDate.toString("yyyy-MM-dd HH:mm:ss") )
( "executionDate", DateFormaterService.getDisplayDate(executionDate) )
, ( "runDate" , DateFormaterService.getDisplayDate(runDate) )
, ( "severity" , severity )
, ( "ruleName" , escapeHTML(ruleName) )
, ( "directiveName", escapeHTML(directiveName) )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ import net.liftweb.http.js.JsCmd
import net.liftweb.http.js.JsCmds._
import net.liftweb.util.Helpers._
import org.joda.time.format.DateTimeFormat

import scala.xml.NodeSeq
import scala.xml.NodeSeq.seqToNodeSeq
import com.normation.appconfig.ReadConfigService
import com.normation.rudder.domain.policies.PolicyMode
import com.normation.rudder.web.ChooseTemplate
import com.normation.rudder.domain.nodes.NodeState

import com.normation.box._
import org.joda.time.DateTime


/**
* Display the last reports of a server
Expand All @@ -71,6 +73,7 @@ class ReportDisplayer(
, reportingService : ReportingService
, techniqueRepository : TechniqueRepository
, configService : ReadConfigService
, logDisplayer: LogDisplayer
) extends Loggable {

private[this] val getAllNodeInfos = RudderConfig.nodeInfoService.getAll _
Expand Down Expand Up @@ -108,6 +111,16 @@ class ReportDisplayer(
for {
report <- reportingService.findNodeStatusReport(node.id)
data <- getComplianceData(node.id, report)
runDate : Option[DateTime] = report.runInfo match {
case a : ComputeCompliance => Some(a.lastRunDateTime)
case a : LastRunAvailable => Some(a.lastRunDateTime)
case a : NoExpectedReport => Some(a.lastRunDateTime)
case a : NoReportInInterval => None
case a : Pending => a.optLastRun.map(_._1)
case a : ReportsDisabledInInterval => None
case NoRunNoExpectedReport => None

}
} yield {
import net.liftweb.util.Helpers.encJs
val intro = encJs(displayIntro(report).toString)
Expand Down Expand Up @@ -304,6 +317,16 @@ class ReportDisplayer(
directiveLib <- directiveRepository.getFullDirectiveLibrary.toBox
} yield {

val runDate : Option[DateTime] = report.runInfo match {
case a: ComputeCompliance => Some(a.lastRunDateTime)
case a: LastRunAvailable => Some(a.lastRunDateTime)
case a: NoExpectedReport => Some(a.lastRunDateTime)
case a: NoReportInInterval => None
case a: Pending => a.optLastRun.map(_._1)
case a: ReportsDisabledInInterval => None
case NoRunNoExpectedReport => None
}

val intro = displayIntro(report)

def triggerAgent(node: NodeInfo) : NodeSeq = {
Expand Down Expand Up @@ -334,6 +357,7 @@ class ReportDisplayer(
* And if don't even have expected configuration, don't display anything.
*/


report.runInfo match {
case NoRunNoExpectedReport | _:NoExpectedReport =>
(
Expand Down Expand Up @@ -366,6 +390,12 @@ class ReportDisplayer(
"lastreportgrid-intro" #> intro
& "runagent" #> triggerAgent(node)
& "lastreportgrid-grid" #> showReportDetail(filtered, node, withCompliance = false)
& "#AllLogButton [class+]" #> { if (runDate.isEmpty) "hide" else "" }
& "#AllLogButton [onClick]" #> { if (runDate.nonEmpty) {
val init = AnonFunc(logDisplayer.asyncDisplay(node.id,runDate,"complianceLogsGrid"))
val refresh = AnonFunc(logDisplayer.ajaxRefresh(node.id,runDate, "complianceLogsGrid"))
s"""showHideRunLogs("#logRun", ${init.toJsCmd}, ${refresh.toJsCmd})"""
} else "" }
& "lastreportgrid-missing" #> NodeSeq.Empty
& "lastreportgrid-unexpected" #> NodeSeq.Empty
)(reportByNodeTemplate)
Expand All @@ -379,6 +409,12 @@ class ReportDisplayer(
"lastreportgrid-intro" #> intro
& "runagent" #> triggerAgent(node)
& "lastreportgrid-grid" #> showReportDetail(report, node, withCompliance = true)
& "#AllLogButton [class+]" #> { if (runDate.isEmpty) "hide" else "" }
& "#AllLogButton [onClick]" #> { if (runDate.nonEmpty) {
val init = AnonFunc(logDisplayer.asyncDisplay(node.id,runDate,"complianceLogsGrid"))
val refresh = AnonFunc(logDisplayer.ajaxRefresh(node.id,runDate, "complianceLogsGrid"))
s"""showHideRunLogs("#logRun",${init.toJsCmd}, ${refresh.toJsCmd})"""
} else "" }
& "lastreportgrid-missing" #> showMissingReports(missing)
& "lastreportgrid-unexpected" #> showUnexpectedReports(unexpected)
)(reportByNodeTemplate)
Expand Down Expand Up @@ -574,4 +610,6 @@ class ReportDisplayer(
""") )
}



}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading