Skip to content

Commit

Permalink
Fixes #23856: Migrate away from NodeInfoService
Browse files Browse the repository at this point in the history
  • Loading branch information
fanf committed Dec 20, 2023
1 parent 26449ec commit f8f32cf
Show file tree
Hide file tree
Showing 46 changed files with 1,057 additions and 936 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,21 @@ import com.normation.errors._
import com.normation.inventory.domain.NodeId
import com.normation.rudder.domain.logger.AllReportLogger
import com.normation.rudder.domain.logger.ScheduledJobLogger
import com.normation.rudder.domain.nodes.NodeInfo
import com.normation.rudder.domain.policies.Rule
import com.normation.rudder.domain.policies.RuleId
import com.normation.rudder.domain.reports.Reports
import com.normation.rudder.facts.nodes.CoreNodeFact
import com.normation.rudder.facts.nodes.NodeFactRepository
import com.normation.rudder.facts.nodes.QueryContext
import com.normation.rudder.repository.FullActiveTechniqueCategory
import com.normation.rudder.repository.ReportsRepository
import com.normation.rudder.repository.RoDirectiveRepository
import com.normation.rudder.repository.RoRuleRepository
import com.normation.rudder.repository.RudderPropertiesRepository
import com.normation.rudder.services.nodes.NodeInfoService
import com.normation.zio._
import net.liftweb.actor._
import net.liftweb.common._
import scala.collection.MapView

/**
* This object will be used as message for the non compliant reports logger
Expand All @@ -71,7 +73,7 @@ class AutomaticReportLogger(
reportsRepository: ReportsRepository,
ruleRepository: RoRuleRepository,
directiveRepository: RoDirectiveRepository,
nodeInfoService: NodeInfoService,
nodeFactRepository: NodeFactRepository,
reportLogInterval: Int
) {

Expand Down Expand Up @@ -113,7 +115,7 @@ class AutomaticReportLogger(
logger.warn("Automatic report logger has never run, logging latest 100 non compliant reports")
val isSuccess = (for {
hundredReports <- reportsRepository.getLastHundredErrorReports(reportsKind).toIO
nodes <- nodeInfoService.getAll()
nodes <- nodeFactRepository.getAll()(QueryContext.systemQC)
rules <- ruleRepository.getAll(true)
directives <- directiveRepository.getFullDirectiveLibrary()
} yield {
Expand Down Expand Up @@ -183,7 +185,7 @@ class AutomaticReportLogger(
fromId: Long,
maxId: Long,
batchSize: Int,
allNodes: Map[NodeId, NodeInfo],
allNodes: MapView[NodeId, CoreNodeFact],
rules: Map[RuleId, Rule],
directives: FullActiveTechniqueCategory
): Box[Long] = {
Expand All @@ -207,7 +209,7 @@ class AutomaticReportLogger(
fromId: Long,
maxId: Long,
batchSize: Int,
nodes: Map[NodeId, NodeInfo],
nodes: MapView[NodeId, CoreNodeFact],
rules: Map[RuleId, Rule],
directives: FullActiveTechniqueCategory
): Box[Long] = {
Expand All @@ -229,7 +231,7 @@ class AutomaticReportLogger(
val startAt = lastProcessedId + 1
logger.debug(s"Writing non-compliant-report logs between ids ${startAt} and ${maxId} (both included)")
(for {
nodes <- nodeInfoService.getAll()
nodes <- nodeFactRepository.getAll()(QueryContext.systemQC)
rules <- ruleRepository.getAll(true)
directives <- directiveRepository.getFullDirectiveLibrary()
} yield {
Expand Down Expand Up @@ -263,7 +265,7 @@ class AutomaticReportLogger(

def logReports(
reports: Seq[(Long, Reports)],
allNodes: Map[NodeId, NodeInfo],
allNodes: MapView[NodeId, CoreNodeFact],
rules: Map[RuleId, Rule],
directives: FullActiveTechniqueCategory
): Option[Long] = {
Expand All @@ -275,7 +277,7 @@ class AutomaticReportLogger(
val t = report.executionDate.toString("yyyy-MM-dd HH:mm:ssZ")
val s = report.severity
val nid = report.nodeId.value
val n = allNodes.get(report.nodeId).map(_.hostname).getOrElse("Unknown node")
val n = allNodes.get(report.nodeId).map(_.fqdn).getOrElse("Unknown node")
val rid = report.ruleId.serialize
val r = rules.get(report.ruleId).map(_.name).getOrElse("Unknown rule")
val did = report.directiveId.debugString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ object JsonPropertySerialisation {
buildHierarchy(list => list.reverse.map(_.toJson))
}

def toApiJsonRenderParents = {
def toApiJsonRenderParents: JObject = {
buildHierarchy(list => {
list.reverse
.map(p => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ trait NodeInfoMatcher {
}

object NodeInfoMatcher {
// default builder: it will evaluated each time, sufficiant if all parts of the matcher uses NodeInfo
// default builder: it will evaluated each time, sufficient if all parts of the matcher uses NodeInfo
def apply(s: String, f: NodeInfo => Boolean): NodeInfoMatcher = {
new NodeInfoMatcher {
override val debugString: String = s
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@

package com.normation.rudder.facts.nodes

import com.normation.box._
import com.normation.eventlog.EventActor
import com.normation.eventlog.ModificationId
import com.normation.inventory.domain._
import com.normation.inventory.domain.{Version => SVersion}
import com.normation.rudder.apidata.NodeDetailLevel
import com.normation.rudder.domain.eventlog
import com.normation.rudder.domain.logger.PolicyGenerationLogger
import com.normation.rudder.domain.nodes.MachineInfo
import com.normation.rudder.domain.nodes.Node
import com.normation.rudder.domain.nodes.NodeInfo
import com.normation.rudder.domain.nodes.NodeKeyHash
import com.normation.rudder.domain.nodes.NodeKind
import com.normation.rudder.domain.nodes.NodeState
import com.normation.rudder.domain.policies.PolicyMode
Expand All @@ -57,10 +60,14 @@ import com.normation.rudder.domain.servers.Srv
import com.normation.rudder.reports._
import com.normation.utils.ParseVersion
import com.normation.utils.Version
import com.normation.zio._
import com.softwaremill.quicklens._
import com.typesafe.config.ConfigRenderOptions
import com.typesafe.config.ConfigValue
import java.net.InetAddress
import net.liftweb.common.Box
import net.liftweb.common.EmptyBox
import net.liftweb.common.Full
import net.liftweb.json.JsonAST
import net.liftweb.json.JsonAST._
import net.liftweb.json.JsonAST.JValue
Expand Down Expand Up @@ -845,6 +852,89 @@ trait MinimalNodeFactInterface {
def timezone: Option[NodeTimezone]
def archDescription: Option[String]
def ram: Option[MemorySize]

// this is copied from NodeInfo. Not sure if there is a better way for now.
/**
* Get a digest of the key in the proprietary CFEngine digest format. It is
* formated as expected by CFEngine authentication module, i.e with the
* "MD5=" prefix for community agent (resp. "SHA=") prefix for enterprise agent).
*/
lazy val keyHashCfengine: String = {

def formatDigest(digest: Box[String], algo: String, tokenType: SecurityToken): String = {
digest match {
case Full(hash) => s"${algo}=${hash}"
case eb: EmptyBox =>
val msgForToken = tokenType match {
case _: PublicKey => "of CFEngine public key for"
case _: Certificate => "for certificate of"
}
val e = eb ?~! s"Error when trying to get the CFEngine-${algo} digest ${msgForToken} node '${fqdn}' (${id.value})"
PolicyGenerationLogger.error(e.messageChain)
""
}
}

(rudderAgent.agentType, rudderAgent.securityToken) match {

case (AgentType.CfeCommunity, key: PublicKey) =>
formatDigest(NodeKeyHash.getCfengineMD5Digest(key).toBox, "MD5", key)

case (AgentType.CfeEnterprise, key: PublicKey) =>
formatDigest(NodeKeyHash.getCfengineSHA256Digest(key).toBox, "SHA", key)

case (AgentType.CfeCommunity, cert: Certificate) =>
formatDigest(NodeKeyHash.getCfengineMD5CertDigest(cert).toBox, "MD5", cert)

case (AgentType.CfeEnterprise, cert: Certificate) =>
formatDigest(NodeKeyHash.getCfengineSHA256CertDigest(cert).toBox, "SHA", cert)

case (AgentType.Dsc, _) =>
PolicyGenerationLogger.info(
s"Node '${fqdn}' (${id.value}) is a Windows node and a we do not know how to generate a hash yet"
)
""

case (_, _) =>
PolicyGenerationLogger.info(
s"Node '${fqdn}' (${id.value}) has an unsuported key type (CFEngine agent with certificate?) and a we do not know how to generate a hash yet"
)
""
}
}

/**
* Get a base64 sha-256 digest (of the DER byte sequence) of the key.
*
* This method never fails, and if we are not able to parse
* the store key, or if no key is store, it return an empty
* string. Logs are used to track problems.
*
*/
lazy val keyHashBase64Sha256: String = {
rudderAgent.securityToken match {
case publicKey: PublicKey =>
NodeKeyHash.getB64Sha256Digest(publicKey).either.runNow match {
case Right(hash) =>
hash
case Left(e) =>
PolicyGenerationLogger.error(
s"Error when trying to get the sha-256 digest of CFEngine public key for node '${fqdn}' (${id.value}): ${e.fullMsg}"
)
""
}
case cert: Certificate =>
NodeKeyHash.getB64Sha256Digest(cert).either.runNow match {
case Right(hash) => hash
case Left(e) =>
PolicyGenerationLogger.error(
s"Error when trying to get the sha-256 digest of Certificate for node '${fqdn}' (${id.value}): ${e.fullMsg}"
)
""
}
}
}

}

/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,10 @@ trait GetNodesbySofwareName {
def apply(softName: String): IOResult[List[(NodeId, Software)]]
}

object NoopGetNodesbySofwareName extends GetNodesbySofwareName {
override def apply(softName: String): IOResult[List[(NodeId, Software)]] = Nil.succeed
}

// default implementation is just a proxy on top of software dao
class SoftDaoGetNodesbySofwareName(val softwareDao: ReadOnlySoftwareDAO) extends GetNodesbySofwareName {
override def apply(softName: String): IOResult[List[(NodeId, Software)]] = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,12 @@ import com.normation.rudder.batch.AsyncDeploymentActor
import com.normation.rudder.batch.AutomaticStartDeployment
import com.normation.rudder.domain.eventlog.RudderEventActor
import com.normation.rudder.facts.nodes.NodeFact
import com.normation.rudder.facts.nodes.NodeFactRepository
import com.normation.rudder.facts.nodes.NodeFactStorage
import com.normation.rudder.facts.nodes.QueryContext
import com.normation.rudder.hooks.HookEnvPairs
import com.normation.rudder.hooks.PureHooksLogger
import com.normation.rudder.hooks.RunHooks
import com.normation.rudder.services.nodes.NodeInfoService
import com.normation.utils.StringUuidGenerator
import com.normation.zio.currentTimeMillis
import zio._
Expand Down Expand Up @@ -116,7 +117,7 @@ class PostCommitInventoryHooks[A](

class FactRepositoryPostCommit[A](
nodeFactsRepository: NodeFactStorage,
nodeInfoService: NodeInfoService
nodeFactRepository: NodeFactRepository
) extends PostCommit[A] {
override def name: String = "commit node in fact-repository"

Expand All @@ -126,11 +127,8 @@ class FactRepositoryPostCommit[A](
*/
override def apply(inventory: Inventory, records: A): IOResult[A] = {
(for {
optInfo <- inventory.node.main.status match {
case AcceptedInventory => nodeInfoService.getNodeInfo(inventory.node.main.id)
case PendingInventory => nodeInfoService.getPendingNodeInfo(inventory.node.main.id)
case RemovedInventory => None.succeed
}
optInfo <- if (inventory.node.main.status == RemovedInventory) None.succeed
else nodeFactRepository.getCompat(inventory.node.main.id, inventory.node.main.status)(QueryContext.systemQC)
_ <- optInfo match {
case None =>
InventoryProcessingLogger.info(
Expand All @@ -142,7 +140,7 @@ class FactRepositoryPostCommit[A](
case Some(nodeInfo) =>
nodeFactsRepository.save(
NodeFact.fromCompat(
nodeInfo,
nodeInfo.toNodeInfo,
Right(FullInventory(inventory.node, Some(inventory.machine))),
inventory.applications
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ import better.files._
import com.normation.errors._
import com.normation.rudder.domain.logger.ScheduledJobLoggerPure
import com.normation.rudder.domain.reports.ComplianceLevel
import com.normation.rudder.facts.nodes.NodeFactRepository
import com.normation.rudder.facts.nodes.QueryContext
import com.normation.rudder.facts.nodes.SelectNodeStatus
import com.normation.rudder.git.GitRepositoryProvider
import com.normation.rudder.git.GitRepositoryProviderImpl
import com.normation.rudder.services.nodes.NodeInfoService
import com.normation.rudder.services.reports.ReportingService
import com.normation.zio._
import java.nio.charset.StandardCharsets
Expand Down Expand Up @@ -133,7 +135,7 @@ class HistorizeNodeCountService(
* Default implementation of `FetchDataService` is just a call to relevant rudder service to get node and reporting
* info (to know if node actual policy mode)
*/
class FetchDataServiceImpl(nodeInfoService: NodeInfoService, reportingService: ReportingService) extends FetchDataService {
class FetchDataServiceImpl(nodeFactRepo: NodeFactRepository, reportingService: ReportingService) extends FetchDataService {

def getFrequentNodeMetric(): IOResult[FrequentNodeMetrics] = {
// a method that returns "e" if compliance is enforce only,
Expand All @@ -150,9 +152,9 @@ class FetchDataServiceImpl(nodeInfoService: NodeInfoService, reportingService: R
}

(for {
accepted <- nodeInfoService.getAll()
pending <- nodeInfoService.getPendingNodeInfos()
compliance <- reportingService.getUserNodeStatusReports().toIO
accepted <- nodeFactRepo.getAll()(QueryContext.systemQC, SelectNodeStatus.Accepted)
pending <- nodeFactRepo.getAll()(QueryContext.systemQC, SelectNodeStatus.Pending)
compliance <- reportingService.getUserNodeStatusReports()(QueryContext.systemQC).toIO
} yield {
val modes = compliance.values.groupMapReduce(r => mode(r.compliance))(_ => 1)(_ + _)
FrequentNodeMetrics(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,8 @@

package com.normation.rudder.reports

import com.normation.box._
import com.normation.errors.RudderError
import com.normation.errors.Unexpected
import com.normation.inventory.domain.NodeId
import com.normation.rudder.domain.Constants
import com.normation.rudder.services.nodes.NodeInfoService
import net.liftweb.common._
import org.joda.time.Duration

Expand Down Expand Up @@ -96,17 +92,9 @@ final case class ResolvedAgentRunInterval(interval: Duration, heartbeatPeriod: I

trait AgentRunIntervalService {
def getGlobalAgentRun(): Box[AgentRunInterval]

/**
* For each node Id passed as argument, find the corresponding
* run interval and heartbeat value (using global default if needed)
*/
def getNodeReportingConfigurations(nodeIds: Set[NodeId]): Box[Map[NodeId, ResolvedAgentRunInterval]]

}

class AgentRunIntervalServiceImpl(
nodeInfoService: NodeInfoService,
readGlobalInterval: () => Box[Int],
readGlobalStartHour: () => Box[Int],
readGlobalStartMinute: () => Box[Int],
Expand All @@ -130,34 +118,6 @@ class AgentRunIntervalServiceImpl(
)
}
}

override def getNodeReportingConfigurations(nodeIds: Set[NodeId]): Box[Map[NodeId, ResolvedAgentRunInterval]] = {
for {
gInterval <- readGlobalInterval()
gHeartbeat <- readGlobalHeartbeat()
nodeInfos <- nodeInfoService.getAll().toBox
} yield {
nodeIds.map { nodeId =>
if (nodeId == Constants.ROOT_POLICY_SERVER_ID) {
// special case. The root policy server always run each 5 minutes
(nodeId, ResolvedAgentRunInterval(Duration.standardMinutes(5), 1))
} else {
val node = nodeInfos.get(nodeId)
val run: Int = node.flatMap {
_.nodeReportingConfiguration.agentRunInterval.flatMap(x =>
if (x.overrides.getOrElse(false)) Some(x.interval) else None
)
}.getOrElse(gInterval)
val heartbeat = node.flatMap {
_.nodeReportingConfiguration.heartbeatConfiguration.flatMap(x => if (x.overrides) Some(x.heartbeatPeriod) else None)
}.getOrElse(gHeartbeat)

(nodeId, ResolvedAgentRunInterval(Duration.standardMinutes(run.toLong), heartbeat))
}
}.toMap
}
}

}

import ca.mrvisser.sealerate.values
Expand Down

0 comments on commit f8f32cf

Please sign in to comment.