Skip to content
Draft
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
@@ -1,3 +1,4 @@

#####################################################################################
# Copyright 2011 Normation SAS
#####################################################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,12 @@ attributetype ( RudderAttributes:111
DESC 'Unique identifier for a Rule category'
SUP uuid )

attributetype ( RudderAttributes:111
NAME 'scheduleId'
DESC 'Unique identifier for a schedule'
SUP uuid )


#######################################################################

attributetype ( RudderAttributes:201
Expand Down Expand Up @@ -517,7 +523,8 @@ objectclass ( RudderObjectClasses:23
STRUCTURAL
MUST ( directiveId $ techniqueVersion )
MAY ( cn $ description $ longDescription $ isEnabled $ isSystem $ revision $
directivePriority $ directiveVariable $ policyMode $ serializedTags $ securityTag) )
directivePriority $ directiveVariable $ policyMode $ serializedTags $
securityTag $ scheduleId) )

### rules ###

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ import com.normation.rudder.ncf.CompilationStatusAllSuccess
import com.normation.rudder.ncf.CompilationStatusErrors
import com.normation.rudder.services.eventlog.EventLogDeploymentService
import com.normation.rudder.services.marshalling.DeploymentStatusSerialisation
import com.normation.rudder.services.policies.PromiseGenerationService
import com.normation.rudder.services.policies.PolicyGenerationService
import com.normation.zio.*
import enumeratum.*
import enumeratum.EnumEntry.*
Expand Down Expand Up @@ -176,7 +176,7 @@ trait AsyncDeploymentAgent {
}

final class AsyncDeploymentActor(
deploymentService: PromiseGenerationService,
deploymentService: PolicyGenerationService,
eventLogger: EventLogDeploymentService,
deploymentStatusSerialisation: DeploymentStatusSerialisation,
getGenerationDelay: () => IOResult[Duration],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ object CampaignId {
sealed trait CampaignStatusValue extends EnumEntry {
def value: String
}

@jsonDiscriminator("value")
sealed trait CampaignStatus {
def value: CampaignStatusValue
Expand Down Expand Up @@ -244,6 +245,7 @@ case class MonthlySchedule(
) extends CampaignSchedule {
override def atTimeZone(timeZone: ScheduleTimeZone): CampaignSchedule = copy(tz = Some(timeZone))
}

@jsonHint("weekly")
case class WeeklySchedule(
start: DayTime,
Expand All @@ -252,6 +254,7 @@ case class WeeklySchedule(
) extends CampaignSchedule {
override def atTimeZone(timeZone: ScheduleTimeZone): CampaignSchedule = copy(tz = Some(timeZone))
}

@jsonHint("one-shot")
case class OneShot(start: DateTime, end: DateTime) extends CampaignSchedule {
override def tz: None.type = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,9 @@ object Doobie {
Read[(NodeId, NodeConfigId, DateTime, Option[DateTime], String)].map(tuple => {
parseJsonNodeExpectedReports(tuple._5) match {
case Full(x) =>
Right(NodeExpectedReports(tuple._1, tuple._2, tuple._3, tuple._4, x.modes, x.ruleExpectedReports, x.overrides))
Right(
NodeExpectedReports(tuple._1, tuple._2, tuple._3, tuple._4, x.modes, x.schedules, x.ruleExpectedReports, x.overrides)
)
case eb: EmptyBox =>
Left((tuple._1, tuple._2, tuple._3))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ object RudderLDAPConstants extends Loggable {
val A_ACTIVE_TECHNIQUE_UUID = "activeTechniqueId"
val A_NODE_GROUP_UUID = "nodeGroupId"
val A_RULE_UUID = "ruleId"
val A_SCHEDULE_ID = "scheduleId"

/* other things */
val A_TECHNIQUE_LIB_VERSION = "techniqueLibraryVersion"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import com.normation.cfclerk.domain.SectionSpec
import com.normation.cfclerk.domain.TechniqueVersion
import com.normation.rudder.tenants.HasSecurityTag
import com.normation.rudder.tenants.SecurityTag
import com.normation.rudder.campaigns.CampaignId
import scala.xml.*

/*
Expand Down Expand Up @@ -142,73 +143,77 @@ object DirectiveId {
final case class Directive(
// As of 7.0, an identifier is a couple of (object uuid, revision id).
// see rational in comment above
id: DirectiveId,

id: DirectiveId,
/**
* They reference one and only one Technique version
*/

techniqueVersion: TechniqueVersion,

/**
* The list or parameters with their values.
* TODO: I really would like to be able to not allow to set bad parameter here,
* what mean parameter that are not in the technique.
* For now, say it's done by construction.
*/
parameters: Map[String, Seq[String]],

parameters: Map[String, Seq[String]],
/**
* A human readable name for that directive,
* typically used for CSV/grid header
* i.e: "SEC-042 Debian Etch"
* Can not be empty nor null.
*/
name: String,

name: String,
/**
* Short description, typically used as field description
* Can not be empty nor null.
*/

shortDescription: String,

/**
* Policy mode defined for that Directive
* Three possibles values for now:
* None => Default (use global mode)
* Some => Verify or Enforce
*/
policyMode: Option[PolicyMode],

policyMode: Option[PolicyMode],
/**
* A long, detailed description, typically used for
* tooltip. It allows reach content.
* Can be empty (and is by default).
*/
longDescription: String = "",

longDescription: String = "",
/**
* For policies which allows only one configured instance at
* a given time for a given node, priority allows to choose
* the policy to deploy.
* Higher priority is better, default is 5
*/
priority: Int = 5,

priority: Int = 5,
/**
* Define if the policy is activated.
* If it is not, configuration based on that policy should not be considered
* for deployment on nodes.
*/
_isEnabled: Boolean = false,
isSystem: Boolean = false,

_isEnabled: Boolean = false,
isSystem: Boolean = false,
/**
* Optionally, Directive can have Tags
*/
tags: Tags = Tags(Set()),

tags: Tags = Tags(Set()),
// security so that in json is becomes: { "security": { "tenants": [...] }, ...}
security: Option[SecurityTag] // optional for backward compat. None means "no tenant"
security: Option[SecurityTag], // optional for backward compat. None means "no tenant"
/**
* Directive may have a schedule. A schedule generates event that
* ask for the agent to run the or not the directive.
* This is None by default, for compat with previous version of Rudder.
*/
scheduleId: Option[CampaignId] = None
) {
// system object must ALWAYS be ENABLED.
def isEnabled: Boolean = _isEnabled || isSystem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ package com.normation.rudder.domain.policies
import com.normation.errors.*
import enumeratum.*

/*
* Policy mode describes if the policy should be audited or enforced.
*/
sealed trait PolicyMode extends EnumEntry {
def name: String
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ package com.normation.rudder.domain.reports
import com.normation.cfclerk.domain.ReportingLogic
import com.normation.cfclerk.domain.TechniqueVersion
import com.normation.inventory.domain.NodeId
import com.normation.rudder.campaigns.CampaignId
import com.normation.rudder.domain.Constants
import com.normation.rudder.domain.policies.DirectiveId
import com.normation.rudder.domain.policies.GlobalPolicyMode
Expand All @@ -54,6 +55,7 @@ import com.normation.rudder.reports.ComplianceMode
import com.normation.rudder.reports.ComplianceModeName
import com.normation.rudder.reports.GlobalComplianceMode
import com.normation.rudder.reports.ResolvedAgentRunInterval
import com.normation.rudder.schedule.JsonDirectiveSchedule
import com.normation.rudder.services.policies.PolicyId
import net.liftweb.common.Box
import net.liftweb.common.Failure
Expand Down Expand Up @@ -88,6 +90,7 @@ final case class NodeExpectedReports(
beginDate: DateTime,
endDate: Option[DateTime],
modes: NodeModeConfig,
schedules: List[JsonDirectiveSchedule],
ruleExpectedReports: List[RuleExpectedReports],
overrides: List[OverriddenPolicy]
) {
Expand Down Expand Up @@ -125,6 +128,7 @@ final case class DirectiveExpectedReports(
directiveId: DirectiveId,
policyMode: Option[PolicyMode],
policyTypes: PolicyTypes,
scheduleId: Option[CampaignId],
components: List[ComponentExpectedReport]
)

Expand Down Expand Up @@ -205,6 +209,7 @@ object ExpectedReportsSerialisation {
*/
final case class JsonNodeExpectedReports private[reports] (
modes: NodeModeConfig,
schedules: List[JsonDirectiveSchedule],
ruleExpectedReports: List[RuleExpectedReports],
overrides: List[OverriddenPolicy]
)
Expand Down Expand Up @@ -278,12 +283,14 @@ object ExpectedReportsSerialisation {
* ... // same as gar
* },
* },
* "ss": [{"id":"0f6e33e5-b678-490c-b8aa-9520d59f381b", "e":true, "s": { schedule definition },...]
* "rs": [ // rules
* {
* "rid": "4bb75daa-a82f-445a-8e8e-af3e99608ffe", // rule id
* "ds": [ // directives
* {
* "did": "73e069ea-de00-4b5d-a00e-012709b7b462", // directive id
* "sid": "0f6e33e5-b678-490c-b8aa-9520d59f381b", // schedule id, opt
* "cs": [ // components
* { // block
* "bid": "my main block", // block (component) id
Expand Down Expand Up @@ -453,46 +460,35 @@ object ExpectedReportsSerialisation {
}

/*
* In 8.2 we changed the s: Option[Boolean] for isSystem to t: Option[ComplianceTag]
* We still want to be able to decode json with s, but never write it. This is done by
* being sure that when we go from DirectiveExpectedReports to JsonDirectiveExpectedReports8_2,
* we always let the s value to None.
* The chosen strategy means that when there is neither s nor t present in json (ie the common
* case of base policies), we always need to test both. The overhead seems negligible compared
* to burden of having two decoders + orElse
* In 8.2 we changed the s: Option[Boolean] for isSystem to t: Option[PolicyTypes]
* In 9.1, we can abandon "s" old attribute since it was never written since 8.2.
*/
final case class JsonDirectiveExpectedReports8_2(
did: DirectiveId,
pm: Option[PolicyMode],
// the old tag for "isSystem", that we can encounter when reading old json. Never write it.
// If both it and t is present, t wins
s: Option[Boolean],
t: Option[PolicyTypes],
sid: Option[CampaignId],
cs: List[JsonComponentExpectedReport7_1]
) {
def transform: DirectiveExpectedReports = {
val ct = {
t match {
case Some(value) => value
case None =>
s match {
case Some(true) => PolicyTypes.rudderSystem
case _ => PolicyTypes.rudderBase
}
case None => PolicyTypes.rudderBase
}
}
DirectiveExpectedReports(did, pm, ct, cs.map(_.transform))
DirectiveExpectedReports(did, pm, ct, sid, cs.map(_.transform))
}
}
implicit class _JsonDirectiveExpectedReports8_2(x: DirectiveExpectedReports) {
def transform: JsonDirectiveExpectedReports8_2 = {
// optimisation: if policyTypes is exactly base, we skip it
// optimization: if policyTypes is exactly base, we skip it
val t = if (x.policyTypes == PolicyTypes.rudderBase) None else Some(x.policyTypes)
JsonDirectiveExpectedReports8_2(
x.directiveId,
x.policyMode,
None,
t,
x.scheduleId,
x.components.map(_.transform)
)
}
Expand All @@ -508,16 +504,24 @@ object ExpectedReportsSerialisation {
def transform = JsonRuleExpectedReports7_1(x.ruleId, x.directives.map(_.transform))
}

@jsonExplicitEmptyCollections(encoding = false, decoding = false) // needed for compat for ss
final case class JsonNodeExpectedReports7_1(
ms: JsonModes7_1,
ss: List[JsonDirectiveSchedule],
rs: List[JsonRuleExpectedReports7_1],
os: List[JsonOverrides7_1]
) extends JsonNodeExpectedReportV {
def transform: JsonNodeExpectedReports = JsonNodeExpectedReports(ms.transform, rs.map(_.transform), os.map(_.transform))
def transform: JsonNodeExpectedReports = JsonNodeExpectedReports(ms.transform, ss, rs.map(_.transform), os.map(_.transform))
}
implicit class _JsonNodeExpecteReports7_1(x: JsonNodeExpectedReports) {
def transform =
JsonNodeExpectedReports7_1(x.modes.transform, x.ruleExpectedReports.map(_.transform), x.overrides.map(_.transform))
def transform = {
JsonNodeExpectedReports7_1(
x.modes.transform,
x.schedules,
x.ruleExpectedReports.map(_.transform),
x.overrides.map(_.transform)
)
}
}

////////// json codec //////////
Expand Down Expand Up @@ -609,7 +613,7 @@ object ExpectedReportsSerialisation {
}

/*
* We always serialise to 7.1 format
* We always serialize to 7.1 format
*/
implicit class JNodeToJson(val n: JsonNodeExpectedReports) extends AnyVal {
import Version7_1.*
Expand All @@ -621,7 +625,7 @@ object ExpectedReportsSerialisation {
implicit class NodeToJson(val n: NodeExpectedReports) extends AnyVal {
import Version7_1.*
private def toJson7_1 = {
JsonNodeExpectedReports(n.modes, n.ruleExpectedReports, n.overrides).transform
JsonNodeExpectedReports(n.modes, n.schedules, n.ruleExpectedReports, n.overrides).transform
}
def toJson = toJson7_1.toJsonPretty
def toCompactJson = toJson7_1.toJson
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,18 @@ final case class RoReportsExecutionRepositoryImpl(
case (Some(id), Some(config), Some(begin), end, Some(json)) =>
ExpectedReportsSerialisation.parseJsonNodeExpectedReports(json) match {
case Full(x) =>
Some(NodeExpectedReports(NodeId(id), NodeConfigId(config), begin, end, x.modes, x.ruleExpectedReports, x.overrides))
Some(
NodeExpectedReports(
NodeId(id),
NodeConfigId(config),
begin,
end,
x.modes,
x.schedules,
x.ruleExpectedReports,
x.overrides
)
)
case eb: EmptyBox =>
val e = eb ?~! s"Error when deserialising node configuration for node with ID: ${id}, configId: ${config}"
logger.error(e.messageChain)
Expand Down
Loading