Skip to content

Commit

Permalink
Fixes #9315: Update DB schema of expected reports to store policy mode
Browse files Browse the repository at this point in the history
  • Loading branch information
fanf committed Oct 17, 2016
1 parent 9034e47 commit 042a70f
Show file tree
Hide file tree
Showing 31 changed files with 1,676 additions and 935 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
*************************************************************************************
* Copyright 2016 Normation SAS
*************************************************************************************
*
* This file is part of Rudder.
*
* Rudder is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In accordance with the terms of section 7 (7. Additional Terms.) of
* the GNU General Public License version 3, the copyright holders add
* the following Additional permissions:
* Notwithstanding to the terms of section 5 (5. Conveying Modified Source
* Versions) and 6 (6. Conveying Non-Source Forms.) of the GNU General
* Public License version 3, when you create a Related Module, this
* Related Module is not considered as a part of the work and may be
* distributed under the license agreement of your choice.
* A "Related Module" means a set of sources files including their
* documentation that, without modification of the Source Code, enables
* supplementary functions or services in addition to those offered by
* the Software.
*
* Rudder is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Rudder. If not, see <http://www.gnu.org/licenses/>.
*
*************************************************************************************
*/

-- Create the table for the node configuration
CREATE TABLE nodeConfigurations (
nodeId text NOT NULL CHECK (nodeId <> '')
, nodeConfigId text NOT NULL CHECK (nodeConfigId <> '')
, beginDate timestamp with time zone NOT NULL
, endDate timestamp with time zone

-- here, I'm using text but with valid JSON in it, because for now we can't impose postgres > 9.2,
-- and interesting function are on 9.3/9.4. we will be able to migrate with:
-- ALTER TABLE table1 ALTER COLUMN col1 TYPE JSON USING col1::JSON;

, configuration text NOT NULL CHECK (nodeId <> '' )

-- Primary key is a little complexe because each of nodeId, nodeConfigId, (nodeId, nodeConfigId)
-- can appears several times. We need to also add begin date (and that can broke on a server with
-- time coming back in the past)

, PRIMARY KEY (nodeId, nodeConfigId, beginDate)
);

CREATE INDEX nodeConfigurations_nodeId ON nodeConfigurations (nodeId);
CREATE INDEX nodeConfigurations_nodeConfigId ON nodeConfigurations (nodeConfigId);

-- Add a new index on reportsExecution to allows an outer join between them and nodeConfigurations.
CREATE INDEX reportsexecution_nodeid_nodeconfigid_idx ON ReportsExecution (nodeId, nodeConfigId);
23 changes: 22 additions & 1 deletion rudder-core/src/main/resources/reportsSchema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ CREATE TABLE ReportsExecution (

CREATE INDEX reportsexecution_date_idx ON ReportsExecution (date);
CREATE INDEX reportsexecution_insertionid_idx ON ReportsExecution (insertionId);
CREATE INDEX reportsexecution_nodeid_nodeconfigid_idx ON ReportsExecution (nodeId, nodeConfigId);

/*
*************************************************************************************
Expand All @@ -140,7 +141,6 @@ CREATE SEQUENCE ruleSerialId START 1;
-- that sequence is used for nodeJoinKey value
CREATE SEQUENCE ruleVersionId START 1;


-- Create the table for the reports information
CREATE TABLE expectedReports (
pkId integer PRIMARY KEY DEFAULT nextval('ruleSerialId')
Expand Down Expand Up @@ -197,7 +197,28 @@ CREATE TABLE nodes_info (
, config_ids text
);

-- Create the table for the node configuration
CREATE TABLE nodeConfigurations (
nodeId text NOT NULL CHECK (nodeId <> '')
, nodeConfigId text NOT NULL CHECK (nodeConfigId <> '')
, beginDate timestamp with time zone NOT NULL
, endDate timestamp with time zone

-- here, I'm using text but with valid JSON in it, because for now we can't impose postgres > 9.2,
-- and interesting function are on 9.3/9.4. we will be able to migrate with:
-- ALTER TABLE table1 ALTER COLUMN col1 TYPE JSON USING col1::JSON;

, configuration text NOT NULL CHECK (nodeId <> '' )

-- Primary key is a little complexe because each of nodeId, nodeConfigId, (nodeId, nodeConfigId)
-- can appears several times. We need to also add begin date (and that can broke on a server with
-- time coming back in the past)

, PRIMARY KEY (nodeId, nodeConfigId, beginDate)
);

CREATE INDEX nodeConfigurations_nodeId ON nodeConfigurations (nodeId);
CREATE INDEX nodeConfigurations_nodeConfigId ON nodeConfigurations (nodeConfigId);

/*
*************************************************************************************
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ final object DB {
, date : DateTime
, nodeConfigId: Option[String]
, isCompleted : Boolean
, insertionId : Long // PURPOSE ?
, insertionId : Long
) {
def toAgentRun = RudderAgentRun(AgentRunId(NodeId(nodeId), date), nodeConfigId.map(NodeConfigId), isCompleted, insertionId)
}
Expand Down
42 changes: 38 additions & 4 deletions rudder-core/src/main/scala/com/normation/rudder/db/Doobie.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,15 @@ import doobie.contrib.postgresql.pgtypes._
import scalaz.{Failure => _, _}, Scalaz._
import scalaz.concurrent.Task
import org.joda.time.DateTime
import org.postgresql.util.PGobject
import scala.xml.XML
import java.sql.SQLXML
import scala.xml.Elem
import com.normation.rudder.domain.reports.Reports
import com.normation.rudder.domain.reports._
import com.normation.rudder.domain.policies.RuleId
import com.normation.rudder.domain.policies.DirectiveId
import com.normation.inventory.domain.NodeId
import net.liftweb.common._
import scala.language.implicitConversions
import com.normation.rudder.domain.reports.NodeConfigVersions
import com.normation.rudder.domain.reports.NodeConfigId

/**
*
Expand Down Expand Up @@ -111,6 +108,43 @@ object Doobie {
)
}

implicit val NodeConfigIdComposite: Atom[Vector[NodeConfigIdInfo]] = {
Atom[String].xmap(
tuple => NodeConfigIdSerializer.unserialize(tuple)
, obj => NodeConfigIdSerializer.serialize(obj)
)
}

/*
* Do not use that one for extraction, only to save NodeExpectedReports
*/
implicit val SerializeNodeExpectedReportsComposite: Composite[NodeExpectedReports] = {
import ExpectedReportsSerialisation._
Composite[(NodeId, NodeConfigId, DateTime, Option[DateTime], String)].xmap(
tuple => throw new RuntimeException(s"Error: that method should not be used to deserialize NodeExpectedReports")
, ner => (ner.nodeId, ner.nodeConfigId, ner.beginDate, ner.endDate, ner.toJson)
)
}

/*
* As we have some json in NodeExpectedReports, it is expected to fail somewhen like
* at each format update. We need to enforce that.
*/
implicit val DeserializeNodeExpectedReportsComposite: Composite[\/[(NodeId, NodeConfigId, DateTime), NodeExpectedReports]] = {
import ExpectedReportsSerialisation._
Composite[(NodeId, NodeConfigId, DateTime, Option[DateTime], String)].xmap(
tuple => {
parseJsonNodeExpectedReports(tuple._5) match {
case Full(x) =>
\/-(NodeExpectedReports(tuple._1, tuple._2, tuple._3, tuple._4, x.modes, x.ruleExpectedReports))
case eb: EmptyBox =>
-\/((tuple._1, tuple._2, tuple._3))
}
}
, ner => throw new RuntimeException(s"Error: that method should not be used to serialize NodeExpectedReports")
)
}


implicit val XmlMeta: Meta[Elem] =
Meta.advanced[Elem](
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ package com.normation.rudder.domain.logger
import org.slf4j.LoggerFactory
import net.liftweb.common.Logger
import com.normation.rudder.services.reports._
import com.normation.rudder.repository.NodeConfigIdInfo
import com.normation.inventory.domain.NodeId
import com.normation.rudder.reports.ComplianceMode
import com.normation.rudder.reports.ResolvedAgentRunInterval
Expand All @@ -50,6 +49,8 @@ import com.normation.rudder.reports.ChangesOnly
import com.google.common.cache.CacheBuilder
import java.util.concurrent.TimeUnit
import com.google.common.cache.CacheLoader
import com.normation.rudder.domain.reports.NodeConfigIdInfo
import com.normation.rudder.domain.reports.NodeExpectedReports

/**
* Log information about compliance.
Expand Down Expand Up @@ -78,6 +79,9 @@ object ComplianceDebugLogger extends Logger {
implicit class NodeConfigIdInfoToLog(n: NodeConfigIdInfo) {
val toLog: String = s"${n.configId.value}/[${n.creation}-${n.endOfLife.fold("now")(_.toString)}]"
}
implicit class NodeExpectedConfigToLog(n: NodeExpectedReports) {
val toLog: String = s"${n.nodeConfigId.value}/[${n.beginDate}-${n.endDate.fold("now")(_.toString)}]"
}

implicit class RunAndConfigInfoToLog(c: RunAndConfigInfo) {

Expand All @@ -97,7 +101,7 @@ object ComplianceDebugLogger extends Logger {
s"expected NodeConfigId: ${expectedConfigId.toLog}|"+
s" last run: none available (compliance mode is reports-disabled)]"

case Pending(expectedConfigId, optLastRun, expirationDateTime, missingStatus) =>
case Pending(expectedConfigId, optLastRun, expirationDateTime) =>
s"until ${expirationDateTime} expected NodeConfigId: ${expectedConfigId.toLog} |"+
s" last run: ${optLastRun.fold("none (or too old)")(x => s"nodeConfigId: ${x._2.toLog} received at ${x._1}")}"

Expand All @@ -106,18 +110,18 @@ object ComplianceDebugLogger extends Logger {
s" last run: nodeConfigInfo: ${lastRunConfigInfo.toLog} received at ${lastRunDateTime} |"+
s" expired at ${lastRunExpiration}"

case UnexpectedUnknowVersion(lastRunDateTime, lastRunConfigId, expectedConfigInfo, expectedExpiration) =>
s"expected NodeConfigId: ${expectedConfigInfo.toLog} |"+
case UnexpectedUnknowVersion(lastRunDateTime, lastRunConfigId, expectedConfig, expectedExpiration) =>
s"expected NodeConfigId: ${expectedConfig.toLog} |"+
s" last run: nodeConfigId: ${lastRunConfigId.value} received at ${lastRunDateTime} |"+
s" expired at ${expectedExpiration}"

case UnexpectedNoVersion(lastRunDateTime, Some(lastRunConfigInfo), lastRunExpiration, expectedConfigInfo, expectedExpiration) =>
s"expected NodeConfigId: ${expectedConfigInfo.toLog} |"+
case UnexpectedNoVersion(lastRunDateTime, lastRunConfigId, lastRunExpiration, expectedConfig, expectedExpiration) =>
s"expected NodeConfigId: ${expectedConfig.toLog} |"+
s" last run: no configId, received at ${lastRunDateTime} |"+
s" expired at ${lastRunExpiration}"

case x@ComputeCompliance(lastRunDateTime, expectedConfigInfo, expirationDateTime, missingStatus) =>
s"expected NodeConfigId: ${expectedConfigInfo.toLog} |"+
case x@ComputeCompliance(lastRunDateTime, expectedConfig, expirationDateTime) =>
s"expected NodeConfigId: ${expectedConfig.toLog} |"+
s" last run: nodeConfigId: ${x.lastRunConfigId.value} received at ${lastRunDateTime} |"+
s" expired at ${expirationDateTime}"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,40 @@ final object PolicyMode {
}
}

/*
* Compute policy mode for only one directive, taking into account the fact that it is system
* (and in that case, it's always "Enforce")
*/
def directivePolicyMode(globalValue : GlobalPolicyMode, nodeMode : Option[PolicyMode], directiveMode : Option[PolicyMode], isSystem: Boolean): PolicyMode = {
if(isSystem) Enforce
else globalValue.overridable match {
case PolicyModeOverrides.Always =>
nodeMode match {
case Some(Audit) => Audit
case _ => directiveMode match {
case Some(Audit) => Audit
case _ => directiveMode.getOrElse(nodeMode.getOrElse(globalValue.mode))
}
}

case PolicyModeOverrides.Unoverridable =>
globalValue.mode
}
}

def computeMode(globalValue : GlobalPolicyMode, nodeMode : Option[PolicyMode]): PolicyMode = {
globalValue.overridable match {
case PolicyModeOverrides.Always =>
nodeMode match {
case Some(Audit) => Audit
case _ => nodeMode.getOrElse(globalValue.mode)
}

case PolicyModeOverrides.Unoverridable =>
globalValue.mode
}
}

}

/*
Expand Down
Loading

0 comments on commit 042a70f

Please sign in to comment.