diff --git a/rudder-core/src/main/scala/com/normation/cfclerk/domain/Technique.scala b/rudder-core/src/main/scala/com/normation/cfclerk/domain/Technique.scala index c906e093eb8..e61f88e20f0 100644 --- a/rudder-core/src/main/scala/com/normation/cfclerk/domain/Technique.scala +++ b/rudder-core/src/main/scala/com/normation/cfclerk/domain/Technique.scala @@ -39,6 +39,7 @@ package com.normation.cfclerk.domain import com.normation.utils.Utils._ import com.normation.utils.HashcodeCaching +import com.normation.inventory.domain.AgentType /** @@ -69,6 +70,13 @@ case class TechniqueId(name: TechniqueName, version: TechniqueVersion) extends O } } +final case class AgentConfig( + agentType: AgentType + , templates : Seq[TechniqueTemplate] + , files : Seq[TechniqueFile] + , bundlesequence : Seq[BundleName] +) + /** * A structure containing all informations about a technique deprecation */ @@ -86,9 +94,7 @@ case class Technique( id : TechniqueId , name : String , description : String - , templates : Seq[TechniqueTemplate] - , files : Seq[TechniqueFile] - , bundlesequence : Seq[Bundle] + , agentConfigs : List[AgentConfig] , trackerVariableSpec : TrackerVariableSpec , rootSection : SectionSpec //be careful to not split it from the TechniqueId, else you will not have the good spec for the version , deprecrationInfo : Option[TechniqueDeprecationInfo] @@ -105,17 +111,10 @@ case class Technique( require(nonEmpty(name), "Name is required in policy") /** - * Utity method that retrieve the map of all template full name for that policy + * Utity method that retrieve all templates IDs + * Be carefull, you will get all templates for all agents */ - val templatesMap: Map[TechniqueResourceId, TechniqueTemplate] = templates.map(t => (t.id, t)).toMap - - def toLongString: String = { - "## %s [%s-%s] ## \n -> unique:%-5s \n -> %s\n -> templates: %s".format( - name, id.name.value, id.version.toString, - if (isMultiInstance) "false" else "true", - description, - templates.mkString(" : ")) - } + val templatesIds: Set[TechniqueResourceId] = agentConfigs.flatMap(cfg => cfg.templates.map(_.id)).toSet val getAllVariableSpecs = this.rootSection.getAllVariables ++ this.systemVariableSpecs :+ this.trackerVariableSpec } @@ -124,7 +123,7 @@ case class Technique( /** * The representation of a bundle name, used for the bundlesequence */ -case class Bundle(name : String) extends HashcodeCaching +case class BundleName(value : String) extends HashcodeCaching object Technique { def normalizeName(name: String): String = { diff --git a/rudder-core/src/main/scala/com/normation/cfclerk/domain/TechniqueResource.scala b/rudder-core/src/main/scala/com/normation/cfclerk/domain/TechniqueResource.scala index ec1d5d8b7aa..b709faa9d36 100644 --- a/rudder-core/src/main/scala/com/normation/cfclerk/domain/TechniqueResource.scala +++ b/rudder-core/src/main/scala/com/normation/cfclerk/domain/TechniqueResource.scala @@ -37,7 +37,6 @@ package com.normation.cfclerk.domain -import com.normation.utils.HashcodeCaching /** * Representation of a technique resource id. @@ -45,9 +44,15 @@ import com.normation.utils.HashcodeCaching * A resource may be either defined relatively to a technique, or relatively to * the configuration-repository directory (the git root directory). * Template filename extension is mandatory to be ".st". + * + * Agent type is not part of the ID because: + * - for a template, extension must be .st, so if you want different template for + * cfengine and something else, you must have different base name. + * - for a "by path" resources, the path must be different for the resources to be + * different. */ sealed trait TechniqueResourceId { - def name: String + def name: String } /** diff --git a/rudder-core/src/main/scala/com/normation/cfclerk/services/impl/GitTechniqueReader.scala b/rudder-core/src/main/scala/com/normation/cfclerk/services/impl/GitTechniqueReader.scala index 29631ebd9b5..d8983763bd6 100644 --- a/rudder-core/src/main/scala/com/normation/cfclerk/services/impl/GitTechniqueReader.scala +++ b/rudder-core/src/main/scala/com/normation/cfclerk/services/impl/GitTechniqueReader.scala @@ -614,7 +614,7 @@ class GitTechniqueReader( private[this] val dummyTechnique = Technique( TechniqueId(TechniqueName("dummy"),TechniqueVersion("1.0")) - , "dummy", "dummy", Seq(), Seq(), Seq(), TrackerVariableSpec() + , "dummy", "dummy", Nil, TrackerVariableSpec() , SectionSpec("ROOT"), None ) @@ -781,8 +781,8 @@ class GitTechniqueReader( //also add template "by path" val techniques = techniqueInfos.techniques.flatMap { case(_, set) => set.map { case(_, t) => t } } techniques.foreach { t => - val byPath = t.templates.collect { case TechniqueTemplate(id@TechniqueResourceIdByPath(_,_),_,_) => id } ++ - t.files.collect { case TechniqueFile(id@TechniqueResourceIdByPath(_,_),_,_) => id } + val byPath = t.agentConfigs.flatMap(cfg => cfg.templates.collect { case TechniqueTemplate(id@TechniqueResourceIdByPath(_,_),_,_) => id }) ++ + t.agentConfigs.flatMap(cfg => cfg.files.collect { case TechniqueFile(id@TechniqueResourceIdByPath(_,_),_,_) => id }) byPath.foreach { resource => //here, "/" is needed at the begining because diffEntry have one, so if we don't //add it, we won't find is back in modifiedTechnique and diffPathEntries diff --git a/rudder-core/src/main/scala/com/normation/cfclerk/xmlparsers/TechniqueParser.scala b/rudder-core/src/main/scala/com/normation/cfclerk/xmlparsers/TechniqueParser.scala index 351d0fdd135..00790ec5c49 100644 --- a/rudder-core/src/main/scala/com/normation/cfclerk/xmlparsers/TechniqueParser.scala +++ b/rudder-core/src/main/scala/com/normation/cfclerk/xmlparsers/TechniqueParser.scala @@ -44,6 +44,7 @@ import com.normation.cfclerk.exceptions.ParsingException import com.normation.utils.Utils._ import scala.xml._ import net.liftweb.common._ +import com.normation.inventory.domain.AgentType /** * Parse a technique (metadata.xml file) @@ -55,46 +56,54 @@ class TechniqueParser( , systemVariableSpecService : SystemVariableSpecService ) extends Loggable { - def parseXml(node: Node, id: TechniqueId, expectedReportCsvExists: Boolean): Technique = { - //check that node is and has a name attribute - if (node.label.toUpperCase == TECHNIQUE_ROOT) { - node.attribute(TECHNIQUE_NAME) match { + def parseXml(xml: Node, id: TechniqueId, expectedReportCsvExists: Boolean): Technique = { + //check that xml is and has a name attribute + if (xml.label.toUpperCase == TECHNIQUE_ROOT) { + xml.attribute(TECHNIQUE_NAME) match { case Some(nameAttr) if (TechniqueParser.isValidId(id.name.value) && nonEmpty(nameAttr.text)) => val name = nameAttr.text - val compatible = try Some(parseCompatibleTag((node \ COMPAT_TAG).head)) catch { case _:Exception => None } + val compatible = try Some(parseCompatibleTag((xml \ COMPAT_TAG).head)) catch { case _:Exception => None } - val rootSection = sectionSpecParser.parseSectionsInPolicy(node, id, name) + val rootSection = sectionSpecParser.parseSectionsInPolicy(xml, id, name) - val description = ??!((node \ TECHNIQUE_DESCRIPTION).text).getOrElse(name) + val description = ??!((xml \ TECHNIQUE_DESCRIPTION).text).getOrElse(name) - val templates = (node \ PROMISE_TEMPLATES_ROOT \\ PROMISE_TEMPLATE).map(xml => parseTemplate(id, xml) ) - val files = (node \ FILES \\ FILE).map(xml => parseFile(id, xml) ) + val trackerVariableSpec = parseTrackerVariableSpec(xml) - val bundlesequence = (node \ BUNDLES_ROOT \\ BUNDLE_NAME).map(xml => Bundle(xml.text) ) + val systemVariableSpecs = parseSysvarSpecs(xml,id) - val trackerVariableSpec = parseTrackerVariableSpec(node) + val isMultiInstance = ((xml \ TECHNIQUE_IS_MULTIINSTANCE).text.equalsIgnoreCase("true") ) - val systemVariableSpecs = parseSysvarSpecs(node,id) + val longDescription = ??!((xml \ TECHNIQUE_LONG_DESCRIPTION).text).getOrElse("") - val isMultiInstance = ((node \ TECHNIQUE_IS_MULTIINSTANCE).text.equalsIgnoreCase("true") ) - - val longDescription = ??!((node \ TECHNIQUE_LONG_DESCRIPTION).text).getOrElse("") - - val isSystem = ((node \ TECHNIQUE_IS_SYSTEM).text.equalsIgnoreCase("true")) + val isSystem = ((xml \ TECHNIQUE_IS_SYSTEM).text.equalsIgnoreCase("true")) //the technique provides its expected reports if at least one section has a variable of type REPORT_KEYS val providesExpectedReports = expectedReportCsvExists - val deprecationInfo = parseDeprecrationInfo(node) + val deprecationInfo = parseDeprecrationInfo(xml) + + val agentConfigs = ( + (xml \ "AGENT" ).toList.map(agent => parseAgentConfig(id, agent)).flatten ++ + { + //for compability reason, we cheat and make the template/file/bundlesequence under root + //and not in an sub-element be considered as being in + val forCompatibilityAgent = + {(xml \ PROMISE_TEMPLATES_ROOT)} + {(xml \ FILES)} + {(xml \ BUNDLES_ROOT)} + + + parseAgentConfig(id, forCompatibilityAgent) + } + ) val technique = Technique( id , name , description - , templates - , files - , bundlesequence + , agentConfigs , trackerVariableSpec , rootSection , deprecationInfo @@ -123,15 +132,48 @@ class TechniqueParser( technique - case _ => throw new ParsingException("Not a policy node, missing 'name' attribute: %s".format(node)) + case _ => throw new ParsingException("Not a policy xml, missing 'name' attribute: %s".format(xml)) } } else { - throw new ParsingException("Not a policy node, bad node name. Was expecting <%s>, got: %s".format(TECHNIQUE_ROOT,node)) + throw new ParsingException("Not a policy xml, bad xml name. Was expecting <%s>, got: %s".format(TECHNIQUE_ROOT,xml)) + } + } + + /* + * Here, we are parsing xml, that contains the list of templates/files/bundles + * defined for the given agent. + * + * id is for reporting + */ + private[this] def parseAgentConfig(id: TechniqueId, xml: Node): List[AgentConfig] = { + //start to parse agent types for that config. It's a comma separated list + import scala.language.postfixOps + + if(xml.label != "AGENT") { + Nil + } else { + + val agentTypes = (xml \ "@type" text).split(",").map { name => + AgentType.fromValue(name) match { + case Full(agentType) => Some(agentType) + case eb: EmptyBox => + val msg = s"Error when parsing technique with id '${id.toString}', agent type='${name}' is not known and the corresponding config will be ignored" + val e = eb ?~! msg + logger.warn(e.messageChain) + None + } + }.flatten.toList + + val templates = (xml \ PROMISE_TEMPLATES_ROOT \\ PROMISE_TEMPLATE).map(xml => parseTemplate(id, xml) ) + val files = (xml \ FILES \\ FILE).map(xml => parseFile(id, xml) ) + val bundlesequence = (xml \ BUNDLES_ROOT \\ BUNDLE_NAME).map(xml => BundleName(xml.text) ) + + agentTypes.map( agentType => AgentConfig(agentType, templates, files, bundlesequence)) } } - private[this] def parseTrackerVariableSpec(node: Node): TrackerVariableSpec = { - val trackerVariableSpecs = (node \ TRACKINGVAR) + private[this] def parseTrackerVariableSpec(xml: Node): TrackerVariableSpec = { + val trackerVariableSpecs = (xml \ TRACKINGVAR) if(trackerVariableSpecs.size == 0) { //default trackerVariable variable spec for that package TrackerVariableSpec() } else if(trackerVariableSpecs.size == 1) { @@ -143,9 +185,9 @@ class TechniqueParser( } else throw new ParsingException("Only one <%s> tag is allowed the the document, but found %s".format(TRACKINGVAR,trackerVariableSpecs.size)) } - private[this] def parseDeprecrationInfo(node: Node): Option[TechniqueDeprecationInfo] = { + private[this] def parseDeprecrationInfo(xml: Node): Option[TechniqueDeprecationInfo] = { for { - deprecationInfo <- (node \ TECHNIQUE_DEPRECATION_INFO).headOption + deprecationInfo <- (xml \ TECHNIQUE_DEPRECATION_INFO).headOption } yield { val message = deprecationInfo.text if (message.size == 0) { @@ -161,8 +203,8 @@ class TechniqueParser( * Parse the list of system vars used by that policy package. * */ - private[this] def parseSysvarSpecs(node: Node, id:TechniqueId) : Set[SystemVariableSpec] = { - (node \ SYSTEMVARS_ROOT \ SYSTEMVAR_NAME).map{ x => + private[this] def parseSysvarSpecs(xml: Node, id:TechniqueId) : Set[SystemVariableSpec] = { + (xml \ SYSTEMVARS_ROOT \ SYSTEMVAR_NAME).map{ x => try { systemVariableSpecService.get(x.text) } catch { @@ -190,7 +232,7 @@ class TechniqueParser( * to root of configuration repository in place of relative to the technique. * */ - private[this] def parseResource(techniqueId: TechniqueId, node: Node, isTemplate:Boolean): (TechniqueResourceId, String) = { + private[this] def parseResource(techniqueId: TechniqueId, xml: Node, isTemplate:Boolean): (TechniqueResourceId, String) = { def fileToList(f: java.io.File): List[String] = { if(f == null) { @@ -203,17 +245,17 @@ class TechniqueParser( //the default out path for a template with name "name" is "techniqueName/techniqueVersion/name.cf def defaultOutPath(name: String) = s"${techniqueId.name.value}/${techniqueId.version.toString}/${name}${if(isTemplate) TechniqueTemplate.promiseExtension else ""}" - val outPath = (node \ PROMISE_TEMPLATE_OUTPATH).text match { + val outPath = (xml \ PROMISE_TEMPLATE_OUTPATH).text match { case "" => None case path => Some(path) } - val id = node.attribute(PROMISE_TEMPLATE_NAME) match { + val id = xml.attribute(PROMISE_TEMPLATE_NAME) match { case Some(attr) if (attr.size == 1) => // some checking on name val n = attr.text.trim if(n.startsWith("/") || n.endsWith("/")) { - throw new ParsingException(s"Error when parsing xml ${node}. Resource name must not start nor end with '/'") + throw new ParsingException(s"Error when parsing xml ${xml}. Resource name must not start nor end with '/'") } else { if(n.startsWith(RUDDER_CONFIGURATION_REPOSITORY+"/")) { @@ -231,7 +273,7 @@ class TechniqueParser( } } - case _ => throw new ParsingException(s"Error when parsing xml ${node}. Resource name is not defined") + case _ => throw new ParsingException(s"Error when parsing xml ${xml}. Resource name is not defined") } (id, outPath.getOrElse(defaultOutPath(id.name))) } @@ -239,36 +281,36 @@ class TechniqueParser( /** * A file is almost exactly like a Template, safe the include that we don't care of. */ - def parseFile(techniqueId: TechniqueId, node: Node): TechniqueFile = { - if(node.label != FILE) throw new ParsingException(s"Error: try to parse a <${FILE}> node, but actually get: ${node}") + def parseFile(techniqueId: TechniqueId, xml: Node): TechniqueFile = { + if(xml.label != FILE) throw new ParsingException(s"Error: try to parse a <${FILE}> xml, but actually get: ${xml}") // Default value for FILE is false, so we should only check if the value is true and if it is empty it - val included = (node \ PROMISE_TEMPLATE_INCLUDED).text == "true" - val (id, out) = parseResource(techniqueId, node, false) + val included = (xml \ PROMISE_TEMPLATE_INCLUDED).text == "true" + val (id, out) = parseResource(techniqueId, xml, false) TechniqueFile(id, out, included) } - def parseTemplate(techniqueId: TechniqueId, node: Node): TechniqueTemplate = { - if(node.label != PROMISE_TEMPLATE) throw new ParsingException(s"Error: try to parse a <${PROMISE_TEMPLATE}> node, but actually get: ${node}") - val included = !((node \ PROMISE_TEMPLATE_INCLUDED).text == "false") - val (id, out) = parseResource(techniqueId, node, true) + def parseTemplate(techniqueId: TechniqueId, xml: Node): TechniqueTemplate = { + if(xml.label != PROMISE_TEMPLATE) throw new ParsingException(s"Error: try to parse a <${PROMISE_TEMPLATE}> xml, but actually get: ${xml}") + val included = !((xml \ PROMISE_TEMPLATE_INCLUDED).text == "false") + val (id, out) = parseResource(techniqueId, xml, true) TechniqueTemplate(id, out, included) } /** * Parse a marker - * @param node example : + * @param xml example : * * Ubuntu * debian-5 * cfengine-community * - * @return A compatible variable corresponding to the entry node + * @return A compatible variable corresponding to the entry xml */ - def parseCompatibleTag(node: Node): Compatible = { - if(node.label != COMPAT_TAG) throw new ParsingException("CompatibleParser was expecting a <%s> node and get:\n%s".format(COMPAT_TAG, node)) - val os = node \ COMPAT_OS map (n => + def parseCompatibleTag(xml: Node): Compatible = { + if(xml.label != COMPAT_TAG) throw new ParsingException("CompatibleParser was expecting a <%s> xml and get:\n%s".format(COMPAT_TAG, xml)) + val os = xml \ COMPAT_OS map (n => OperatingSystem(n.text, (n \ "@version").text)) - val agents = node \ COMPAT_AGENT map (n => + val agents = xml \ COMPAT_AGENT map (n => Agent(n.text, (n \ "@version").text)) Compatible(os, agents) } diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/policies/RuleVal.scala b/rudder-core/src/main/scala/com/normation/rudder/services/policies/RuleVal.scala index 21f957d537d..3896699479b 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/policies/RuleVal.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/policies/RuleVal.scala @@ -37,22 +37,19 @@ package com.normation.rudder.services.policies -import scala.collection.immutable.TreeMap import com.normation.cfclerk.domain.Technique import com.normation.cfclerk.domain.TrackerVariable import com.normation.cfclerk.domain.Variable -import com.normation.inventory.domain.NodeInventory import com.normation.rudder.domain.nodes.NodeInfo import com.normation.rudder.domain.parameters.ParameterName -import com.normation.rudder.domain.reports.NodeAndConfigId -import com.normation.rudder.services.policies.write.Cf3PolicyDraft -import com.normation.rudder.services.policies.write.Cf3PolicyDraftId -import com.normation.utils.HashcodeCaching -import net.liftweb.common.Box import com.normation.rudder.domain.policies.DirectiveId +import com.normation.rudder.domain.policies.PolicyMode import com.normation.rudder.domain.policies.RuleId import com.normation.rudder.domain.policies.RuleTarget -import com.normation.rudder.domain.policies.PolicyMode +import com.normation.rudder.domain.reports.NodeAndConfigId +import com.normation.utils.HashcodeCaching +import net.liftweb.common.Box +import scala.collection.immutable.TreeMap final case class BundleOrder(value: String) diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/AgentSpecificLogic.scala b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/AgentSpecificLogic.scala index ccfdda6da01..bf8572d5746 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/AgentSpecificLogic.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/AgentSpecificLogic.scala @@ -43,11 +43,8 @@ import java.io.File import net.liftweb.common.Box import net.liftweb.util.Helpers.tryo import com.normation.inventory.domain.AgentType -import com.normation.inventory.domain.COMMUNITY_AGENT -import com.normation.inventory.domain.NOVA_AGENT import com.normation.utils.Control.sequence import net.liftweb.common.Full -import com.normation.inventory.domain.DSC_AGENT import net.liftweb.common.Failure /* @@ -135,7 +132,7 @@ object CFEngineAgentSpecificGeneration extends AgentSpecificGeneration { val GENEREATED_CSV_FILENAME = "rudder_expected_reports.csv" - override def handle(agentType: AgentType): Boolean = agentType == COMMUNITY_AGENT || agentType == NOVA_AGENT + override def handle(agentType: AgentType): Boolean = agentType == AgentType.CfeCommunity || agentType == AgentType.CfeEnterprise override def write(cfg: AgentNodeWritableConfiguration): Box[List[AgentSpecificFile]] = { writeExpectedReportsCsv(cfg.paths, cfg.expectedReportsCsv, GENEREATED_CSV_FILENAME) @@ -166,7 +163,7 @@ object CFEngineAgentSpecificGeneration extends AgentSpecificGeneration { */ object DscAgentSpecificGeneration extends AgentSpecificGeneration { - override def handle(agentType: AgentType): Boolean = agentType == DSC_AGENT + override def handle(agentType: AgentType): Boolean = agentType == AgentType.Dsc override def write(cfg: AgentNodeWritableConfiguration): Box[List[AgentSpecificFile]] = { writeSystemVarJson(cfg.paths) diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/BuildBundleSequence.scala b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/BuildBundleSequence.scala index 1f134f389da..fa38ce391bd 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/BuildBundleSequence.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/BuildBundleSequence.scala @@ -37,7 +37,7 @@ package com.normation.rudder.services.policies.write -import com.normation.cfclerk.domain.Bundle +import com.normation.cfclerk.domain.BundleName import com.normation.cfclerk.domain.Technique import com.normation.inventory.domain.NodeId import com.normation.rudder.domain.policies.GlobalPolicyMode @@ -106,6 +106,14 @@ object BuildBundleSequence { // or in CFEngine name a "promiser" final case class Directive(value: String) + // a Bundle is a BundleName and a Rudder Id that will + // be used to identify reports for that bundle + final case class Bundle(id: ReportId, name: BundleName) + + // The rudder id is directiveid@@ruleid@@serial + final case class ReportId(value: String) + + /* * A to-be-written list of bundle related to a unique * technique. They all have the same Policy name, derived @@ -170,14 +178,18 @@ class BuildBundleSequence(systemVariableSpecService: SystemVariableSpecService) // Then builds bundles and inputs: // - build techniques bundles from the sorted list of techniques - val techniquesBundles = sortedTechniques.toList.map(buildTechniqueBundles(nodeId)).removeEmptyBundle + val techniquesBundles = sortedTechniques.toList.map(buildTechniqueBundles(nodeId, agentType)).removeEmptyBundle // - build list of inputs file to include: all the outPath of templates that should be "included". // (returns the pair of (outpath, isSystem) ) - val inputs: List[InputFile] = sortedTechniques.flatMap {case (technique, _, _) => - technique.templates.collect { case template if(template.included) => InputFile(template.outPath, technique.isSystem) } ++ - technique.files.collect { case file if(file.included) => InputFile(file.outPath, technique.isSystem) } + val inputs: List[InputFile] = sortedTechniques.flatMap {case (technique, _, _, _) => + technique.agentConfigs.find( _.agentType == agentType) match { + case None => Nil + case Some(cfg) => + cfg.templates.collect { case template if(template.included) => InputFile(template.outPath, technique.isSystem) } ++ + cfg.files.collect { case file if(file.included) => InputFile(file.outPath, technique.isSystem) } + } }.toList //split system and user directive (technique) @@ -208,55 +220,73 @@ class BuildBundleSequence(systemVariableSpecService: SystemVariableSpecService) ////////// Implementation details ////////// //////////////////////////////////////////// + /* + * Some Techniques don't have any bundle (at least common). + * We don't want to include these technique in the bundle sequence, + * obviously + */ + implicit final class NoBundleTechnique(bundles: List[TechniqueBundles]) { + def removeEmptyBundle: List[TechniqueBundles] = bundles.filterNot(_.main.isEmpty) + } + /* * For each techniques, build: * - the promiser * - the list of bundle included, + * + * The List[BundleOrder] is actually List(ruleName, directiveName) for the chose couple for that technique. + * The ReportId is the same for all bundles, because we don't have a better granularity for now + * (and it is also why we get it from sortTechniques, which is kind of strange :) + * */ - def buildTechniqueBundles(nodeId: NodeId)(t3: (Technique, List[BundleOrder], PolicyMode)): TechniqueBundles = { + def buildTechniqueBundles(nodeId: NodeId, agentType: AgentType)(t3: (Technique, ReportId, List[BundleOrder], PolicyMode)): TechniqueBundles = { // naming things to make them clear val technique = t3._1 - val name = Directive(t3._2.map(_.value).mkString("/")) - val policyMode = t3._3 + val reportId = t3._2 + val name = Directive(t3._3.map(_.value).mkString("/")) + val policyMode = t3._4 // We need to remove zero-length bundle name from the bundlesequence (like, if there is no ncf bundles to call) // to avoid having two successives commas in the bundlesequence - val techniqueBundles = technique.bundlesequence.flatMap { bundle => - if(bundle.name.trim.size > 0) { - Some(bundle) - } else { - logger.warn(s"Technique '${technique.id}' used in node '${nodeId.value}' contains some bundle with empty name, which is forbidden and so they are ignored in the final bundle sequence") - None - } - }.toList - TechniqueBundles(name, Nil, techniqueBundles, Nil, technique.isSystem, technique.providesExpectedReports, policyMode) - } + // and for now, all bundle get the same reportKey + val techniqueBundles = technique.agentConfigs.find(_.agentType == agentType) match { + case Some(cfg) => + cfg.bundlesequence.map { bundleName => + if(bundleName.value.trim.size > 0) { + List(Bundle(reportId, bundleName)) + } else { + logger.warn(s"Technique '${technique.id}' used in node '${nodeId.value}' contains some bundle with empty name, which is forbidden and so they are ignored in the final bundle sequence") + Nil + } + }.flatten.toList + case None => Nil + } - /* - * Some Techniques don't have any bundle (at least common). - * We don't want to include these technique in the bundle sequence, - * obviously - */ - implicit final class NoBundleTechnique(bundles: List[TechniqueBundles]) { - def removeEmptyBundle: List[TechniqueBundles] = bundles.filterNot(_.main.isEmpty) + TechniqueBundles(name, Nil, techniqueBundles, Nil, technique.isSystem, technique.providesExpectedReports, policyMode) } /* * Sort the techniques according to the order of the associated BundleOrder of Cf3PolicyDraft. - * Sort at best: sort rule then directives, and take techniques on that order, only one time - * Sort system directive first. + * Sort at best: sort rule then directives, and take techniques on that order, only one time. * * CAREFUL: this method only take care of sorting based on "BundleOrder", other sorting (like * "system must go first") are not taken into account here ! + * + * Actually, sortTechnique does more because it is the point where we look if a technique is + * used in several rules/directives and where we choose what rule/directive will be used, + * so we are also looking for: + * - the Audit Mode consistancy (and return it if consistant), + * - the ReportId of the chosen couple. + * */ def sortTechniques( nodeId : NodeId , nodePolicyMode : Option[PolicyMode] , globalPolicyMode: GlobalPolicyMode , container : Cf3PolicyDraftContainer - ): Box[Seq[(Technique, List[BundleOrder], PolicyMode)]] = { + ): Box[Seq[(Technique, ReportId, List[BundleOrder], PolicyMode)]] = { val techniques = container.getTechniques().values.toList @@ -264,41 +294,50 @@ class BuildBundleSequence(systemVariableSpecService: SystemVariableSpecService) BundleOrder.compareList(List(a.ruleOrder, a.directiveOrder), List(b.ruleOrder, b.directiveOrder)) <= 0 } - val drafts = container.cf3PolicyDrafts.values.toSeq + val drafts = container.cf3PolicyDrafts.values.toList for { - //for each technique, get it's best order from draft (if several directive use it) and return a pair (technique, List(order)) - triples <- bestEffort(techniques) { t => + //for each technique, get it's best order from draft (if several directive use it) + techBundle <- bestEffort(techniques) { t => val tDrafts = drafts.filter { _.technique.id == t.id }.sortWith( compareBundleOrder ) - //the order we want is the one with the lowest draft order, or the default one if no draft found (but that should not happen by construction) - val order = tDrafts.map( t => List(t.ruleOrder, t.directiveOrder)).headOption.getOrElse(List(BundleOrder.default)) - - // until we have a directive-level granularity for policy mode, we have to define a technique-level policy mode - // if directives don't have a consistant policy mode, we fail (and report it) - (PolicyMode.computeMode(globalPolicyMode, nodePolicyMode, tDrafts.map(_.policyMode)).map { policyMode => - (t, order, policyMode) - }) match { - case Full(x) => Full(x) - case eb: EmptyBox => - val msg = eb match { - case Empty => "" - case Failure(m, _, _) => ": " + m + tDrafts match { + case Nil => //that should not happen because we only chose techniques with draft, but still + Failure(s"Error with Technique ${t.name} during bundle sequence generation, we found a techniques without any bundle" + + s" for node '${nodeId.value}' but it should not happen. " + + "This is likely a bug, please report it to https://rudder-project.org/issues") + case draft :: _ => + // the bundle full order in the couple (rule name, directive name) + val bundleOrder = List(draft.ruleOrder, draft.directiveOrder) + // the rudderId is homogeneous for the whole technique + val rudderId = ReportId(s"${draft.id.value}@@${draft.serial}") + + // until we have a directive-level granularity for policy mode, we have to define a technique-level policy mode + // if directives don't have a consistant policy mode, we fail (and report it) + (PolicyMode.computeMode(globalPolicyMode, nodePolicyMode, tDrafts.map(_.policyMode)).map { policyMode => + (t, rudderId, bundleOrder, policyMode) + }) match { + case Full(x) => Full(x) + case eb: EmptyBox => + val msg = eb match { + case Empty => "" + case Failure(m, _, _) => ": " + m + } + Failure(s"Error with Technique ${t.name} and [Rule ID // Directives ID: Policy Mode] ${tDrafts.map { x => + s"[${x.id.ruleId.value} // ${x.id.directiveId.value}: ${x.policyMode.map(_.name).getOrElse("inherited")}]" + }.mkString("; ") } ${msg}") } - Failure(s"Error with Technique ${t.name} and [Rule ID // Directives ID: Policy Mode] ${tDrafts.map { x => - s"[${x.id.ruleId.value} // ${x.id.directiveId.value}: ${x.policyMode.map(_.name).getOrElse("inherited")}]" - }.mkString("; ") } ${msg}") } } } yield { - //now just sort the pair by order and keep only techniques - val ordered = triples.sortWith { case ((_, o1, _), (_, o2, _)) => BundleOrder.compareList(o1, o2) <= 0 } + //now that we have the (rule/directive) for each technique, sort techniques + val ordered = techBundle.sortWith { case ((_, _, o1, _), (_, _, o2, _)) => BundleOrder.compareList(o1, o2) <= 0 } //some debug info to understand what order was used for each node: if(logger.isDebugEnabled) { - val sorted = ordered.map(p => s"${p._1.name}: [${p._2.map(_.value).mkString(" | ")}]").mkString("[","][", "]") + val sorted = ordered.map(p => s"${p._1.name}: [${p._3.map(_.value).mkString(" | ")}]").mkString("[","][", "]") logger.debug(s"Sorted Technique (and their Rules and Directives used to sort): ${sorted}") } @@ -347,7 +386,8 @@ object CfengineBundleVariables extends AgentFormatBundleVariables { if(tb.providesExpectedReports) { val newMain = tb.main match { case Nil => Nil - case firstBundle :: tail => (Bundle(s"""current_technique_report_info("${firstBundle.name}")""") + // in that case, we are using the same ReportId for report and bundle + case firstBundle :: tail => (Bundle(firstBundle.id, BundleName(s"""current_technique_report_info("${firstBundle.name.value}")""")) :: firstBundle :: tail) } tb.copy(main = newMain) @@ -378,8 +418,8 @@ object CfengineBundleVariables extends AgentFormatBundleVariables { } //before each technique, set the correct mode - private[this] val audit = Bundle("""set_dry_run_mode("true")""") - private[this] val enforce = Bundle("""set_dry_run_mode("false")""") + private[this] val audit = Bundle(ReportId("internal"), BundleName("""set_dry_run_mode("true")""")) + private[this] val enforce = Bundle(ReportId("internal"), BundleName("""set_dry_run_mode("false")""")) private[this] val cleanup = TechniqueBundles(Directive("remove_dry_run_mode"), Nil, enforce :: Nil, Nil, false, false, PolicyMode.Enforce) } @@ -406,7 +446,7 @@ object CfengineBundleVariables extends AgentFormatBundleVariables { (escapedSeq.flatMap { case (promiser, bundles) => bundles.map { bundle => - s""""${promiser}"${ " " * Math.max(0, alignWidth - promiser.size) } usebundle => ${bundle.name};""" + s""""${promiser}"${ " " * Math.max(0, alignWidth - promiser.size) } usebundle => ${bundle.name.value};""" } }.mkString( "\n")) :: Nil } @@ -441,10 +481,37 @@ object DscBundleVariables extends AgentFormatBundleVariables { , userBundles : List[TechniqueBundles] ) : BundleSequenceVariables = { BundleSequenceVariables( - "plop" :: Nil - , "plop" :: Nil - , "plap" :: Nil - , "plup" :: Nil + // no use of input files in DSC + Nil + // no specific pre/post bundles added for DSC + , formatMethodsUsebundle(sytemBundles) + // no use of input files in DSC + , Nil + // no specific pre/post bundles added for DSC + , formatMethodsUsebundle(userBundles) ) } + + /* + * Method for formating list of "Technique -ReportId XXX -TechniqueName "the name" -AuditMode true " + */ + def formatMethodsUsebundle(bundleSeq: Seq[TechniqueBundles]): List[String] = { + + (bundleSeq.flatMap { technique => + val auditOnly = technique.policyMode match { + case PolicyMode.Audit => "true" + case _ => "false" + } + + technique.bundleSequence.map { bundle => + //we don't have exactly the same output for system and non system technique + if(technique.isSystem) { + s""" ${bundle.name.value} -ReportId ${bundle.id.value} -TechniqueName "${technique.promiser.value}" -auditOnly:$$${auditOnly}""" + } else { + s""" ${bundle.name.value} -ReportId ${bundle.id.value}""" + } + } + }.mkString( "\n")) :: Nil + } + } diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PolicyWriterService.scala b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PolicyWriterService.scala index 37e0a622bb2..3287adbb2d6 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PolicyWriterService.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PolicyWriterService.scala @@ -43,11 +43,10 @@ import com.normation.cfclerk.domain.TechniqueResourceId import com.normation.cfclerk.domain.TechniqueTemplate import com.normation.cfclerk.services.TechniqueRepository import com.normation.inventory.domain.AgentType -import com.normation.inventory.domain.AgentType.CfeCommunity import com.normation.inventory.domain.AgentType.CfeEnterprise import com.normation.inventory.domain.NodeId import com.normation.rudder.domain.Constants -import com.normation.rudder.domain.licenses.NovaLicense +import com.normation.rudder.domain.licenses.CfeEnterpriseLicense import com.normation.rudder.domain.nodes.NodeProperty import com.normation.rudder.domain.policies.GlobalPolicyMode import com.normation.rudder.domain.reports.NodeConfigId @@ -73,6 +72,7 @@ import org.apache.commons.io.FileUtils import org.apache.commons.io.FilenameUtils import org.apache.commons.io.IOUtils import org.joda.time.DateTime +import scala.concurrent.Await import scala.io.Codec import scala.util.{ Failure => FailTry } import scala.util.Success @@ -383,21 +383,29 @@ class Cf3PromisesFileWriterServiceImpl( } } + /* + * We are returning a map where keys are (TechniqueResourceId, AgentType) because + * for a given resource IDs, you can have different out path for different agent. + */ private[this] def readTemplateFromFileSystem( techniqueIds: Set[TechniqueId] - )(implicit scheduler: Scheduler, semaphore: TaskSemaphore): Box[Map[TechniqueResourceId, TechniqueTemplateCopyInfo]] = { + )(implicit scheduler: Scheduler, semaphore: TaskSemaphore): Box[Map[(TechniqueResourceId, AgentType), TechniqueTemplateCopyInfo]] = { //list of (template id, template out path) val templatesToRead = for { technique <- techniqueRepository.getByIds(techniqueIds.toSeq) - template <- technique.templates + template <- technique.agentConfigs.flatMap(cfg => cfg.templates.map(t => (t.id, cfg.agentType, t.outPath))) } yield { - (template.id, template.outPath) + template } val now = System.currentTimeMillis() - val res = (parrallelSequence(templatesToRead) { case (templateId, templateOutPath) => + /* + * NOTE : this is inefficient and store in a lot of multiple time the same content + * if only the outpath change for two differents agent type. + */ + val res = (parrallelSequence(templatesToRead) { case (templateId, agentType, templateOutPath) => for { copyInfo <- techniqueRepository.getTemplateContent(templateId) { optInputStream => optInputStream match { @@ -411,7 +419,7 @@ class Cf3PromisesFileWriterServiceImpl( } } } yield { - (copyInfo.id, copyInfo) + ((copyInfo.id, agentType), copyInfo) } }).map( _.toMap) diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariables.scala b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariables.scala index 6907f4bf958..ae80958c5d1 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariables.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariables.scala @@ -62,6 +62,7 @@ import net.liftweb.common._ import org.joda.time.DateTime import scala.io.Codec import com.normation.inventory.domain.AgentType +import com.normation.cfclerk.domain.TechniqueFile trait PrepareTemplateVariables { @@ -79,7 +80,7 @@ trait PrepareTemplateVariables { agentNodeConfig : AgentNodeConfiguration , nodeConfigVersion: NodeConfigId , rootNodeConfigId : NodeId - , templates : Map[TechniqueResourceId, TechniqueTemplateCopyInfo] + , templates : Map[(TechniqueResourceId, AgentType), TechniqueTemplateCopyInfo] , allNodeConfigs : Map[NodeId, NodeConfiguration] , rudderIdCsvTag : String , globalPolicyMode : GlobalPolicyMode @@ -101,7 +102,7 @@ class PrepareTemplateVariablesImpl( agentNodeConfig : AgentNodeConfiguration , nodeConfigVersion: NodeConfigId , rootNodeConfigId : NodeId - , templates : Map[TechniqueResourceId, TechniqueTemplateCopyInfo] + , templates : Map[(TechniqueResourceId, AgentType), TechniqueTemplateCopyInfo] , allNodeConfigs : Map[NodeId, NodeConfiguration] , rudderIdCsvTag : String , globalPolicyMode : GlobalPolicyMode @@ -128,12 +129,12 @@ class PrepareTemplateVariablesImpl( } yield { val allSystemVars = systemVariables.toMap ++ bundleVars val preparedTemplate = prepareTechniqueTemplate( - agentNodeConfig.config.nodeInfo.id, container, allSystemVars, templates, generationTimestamp + agentNodeConfig.config.nodeInfo.id, agentNodeConfig.agentType, container, allSystemVars, templates, generationTimestamp ) // we only need to generate expected_reports.csv for CFEngine-like agent val csv = ExpectedReportsCsv(agentNodeConfig.agentType match { - case COMMUNITY_AGENT | NOVA_AGENT => + case AgentType.CfeCommunity | AgentType.CfeEnterprise => logger.trace(s"${agentNodeConfig.config.nodeInfo.id.value}: creating lines for expected reports CSV files") prepareReportingDataForMetaTechnique(container, rudderIdCsvTag) case _ => // DSC_AGENT or other @@ -147,9 +148,10 @@ class PrepareTemplateVariablesImpl( private[this] def prepareTechniqueTemplate( nodeId : NodeId // for log message + , agentType : AgentType , container : Cf3PolicyDraftContainer , extraSystemVariables: Map[String, Variable] - , allTemplates : Map[TechniqueResourceId, TechniqueTemplateCopyInfo] + , allTemplates : Map[(TechniqueResourceId, AgentType), TechniqueTemplateCopyInfo] , generationTimestamp : Long ) : Map[TechniqueId, PreparedTechnique] = { @@ -170,14 +172,19 @@ class PrepareTemplateVariablesImpl( val generationVariable = STVariable("GENERATIONTIMESTAMP", false, Seq(generationTimestamp), true) techniques.map {technique => - val techniqueTemplatesIds = technique.templatesMap.keySet + val techniqueTemplatesIds = technique.templatesIds // this is an optimisation to avoid re-redeading template each time, for each technique. We could // just, from a strict correctness point of view, just do a techniquerepos.getcontent for each technique.template here - val techniqueTemplates = allTemplates.filterKeys(k => techniqueTemplatesIds.contains(k)).values.toSet + val techniqueTemplates = allTemplates.filterKeys(k => techniqueTemplatesIds.contains(k._1) && k._2 == agentType).values.toSet val variables = variablesByTechnique(technique.id) :+ rudderParametersVariable :+ generationVariable + val files = (technique.agentConfigs.find( _.agentType == agentType).map( _.files) match { + case None => Set.empty[TechniqueFile] + case Some(x) => x.toSet[TechniqueFile] + }) + ( technique.id - , PreparedTechnique(techniqueTemplates, variables, technique.files.toSet) + , PreparedTechnique(techniqueTemplates, variables, files) ) }.toMap } diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/dsc-agent/1.0/some-resource.conf b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/dsc-agent/1.0/some-resource.conf new file mode 100644 index 00000000000..911d3962d5d --- /dev/null +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/dsc-agent/1.0/some-resource.conf @@ -0,0 +1,3 @@ +Blabla bla bla some conf. + +Done. \ No newline at end of file diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/properties.d/properties.json b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/properties.d/properties.json new file mode 100644 index 00000000000..8f2512d7b40 --- /dev/null +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/properties.d/properties.json @@ -0,0 +1,3 @@ +{ + "properties":{} +} \ No newline at end of file diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder-directives.ps1 b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder-directives.ps1 new file mode 100644 index 00000000000..fa8cbf015d1 --- /dev/null +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder-directives.ps1 @@ -0,0 +1,28 @@ +##################################################################################### +# Copyright 2017 Normation SAS +##################################################################################### +# +# This program 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, Version 3. +# +# This program 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 this program. If not, see . +# +##################################################################################### + +# This file is the main entry points for the bundle sequence for +# Rudder system directives. It is actually a list of method calls. + +function Call_Directives( + [string] $class = $null + ) { + + + technique_test -ReportIdentifier "12346789@@789abcs@@15" -TechniqueName "TestTechnique" -auditOnly:$false +} diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder-system-directives.ps1 b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder-system-directives.ps1 new file mode 100644 index 00000000000..28911c84a1a --- /dev/null +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder-system-directives.ps1 @@ -0,0 +1,40 @@ +##################################################################################### +# Copyright 2017 Normation SAS +##################################################################################### +# +# This program 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, Version 3. +# +# This program 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 this program. If not, see . +# +##################################################################################### + +# This file is the main entry points for the bundle sequence for +# Rudder system directives. It is actually a list of method calls. + +function Call_System_Directives( + [string] $class = $null + ) { + $system_techniques_path = "$rudder_path\system-techniques" + + Write-Verbose ("Loading all system techniques scripts in $system_techniques_path") + + # Get list of all files in ncf folders, and load them + $system_techniques_files = Get-ChildItem -recurse $system_techniques_path -Filter *.ps1 + + $system_techniques_files | ForEach { + . $_.FullName + } + + Write-Verbose ("Loaded all system technique ps1 scripts") + + # configure logging + configure_logger -ReportIdentifier "12346789@@789abcs@@15" +} diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder.json b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder.json new file mode 100644 index 00000000000..172b31c213c --- /dev/null +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder.json @@ -0,0 +1,5 @@ +{ + "syslog_protocol": "udp", + "syslog_port": "514", + "config_id": "0" +} diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder.ps1 b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder.ps1 new file mode 100644 index 00000000000..8be360a5f13 --- /dev/null +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/node-dsc-with-one-directive/rules/dsc/rudder.ps1 @@ -0,0 +1,8 @@ +[CmdletBinding()] +param ( +[Parameter(Mandatory=$true)] +[string] $action = "run", +[string] $class = $null +) + +Write-Error "Not an actual agent" \ No newline at end of file diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/common/1.0/cf-served.cf b/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/common/1.0/cf-served.cf index f7a8704a898..8e18b926d25 100644 --- a/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/common/1.0/cf-served.cf +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/common/1.0/cf-served.cf @@ -61,12 +61,12 @@ bundle server access_rules "/var/rudder/share/root/" maproot => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, admit => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, - admit_keys => { "MD5=" }; + admit_keys => { "MD5=081cf3aac62624ebbc83be7e23cb104d" }; "/var/rudder/shared-files/root/" maproot => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, admit => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, - admit_keys => { "MD5=" }; + admit_keys => { "MD5=081cf3aac62624ebbc83be7e23cb104d" }; diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/distributePolicy/1.0/nodeslist.json b/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/distributePolicy/1.0/nodeslist.json index a16f556b46d..84fffdfc188 100644 --- a/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/distributePolicy/1.0/nodeslist.json +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/root-default-install/distributePolicy/1.0/nodeslist.json @@ -1,7 +1,7 @@ { "root": { "hostname": "server.rudder.local", - "key-hash": "sha256:", + "key-hash": "sha256:cf621af57886d614617b2c8187d1db9d18c93ee0674c9985fb06fa17705ed4f0", "policy-server": "root" } diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/common/1.0/cf-served.cf b/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/common/1.0/cf-served.cf index f7a8704a898..8e18b926d25 100644 --- a/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/common/1.0/cf-served.cf +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/common/1.0/cf-served.cf @@ -61,12 +61,12 @@ bundle server access_rules "/var/rudder/share/root/" maproot => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, admit => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, - admit_keys => { "MD5=" }; + admit_keys => { "MD5=081cf3aac62624ebbc83be7e23cb104d" }; "/var/rudder/shared-files/root/" maproot => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, admit => { host2ip("server.rudder.local"), string_downcase(escape("server.rudder.local")) }, - admit_keys => { "MD5=" }; + admit_keys => { "MD5=081cf3aac62624ebbc83be7e23cb104d" }; diff --git a/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/distributePolicy/1.0/nodeslist.json b/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/distributePolicy/1.0/nodeslist.json index a16f556b46d..84fffdfc188 100644 --- a/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/distributePolicy/1.0/nodeslist.json +++ b/rudder-core/src/test/resources/configuration-repository/expected-share/root-with-two-directives/distributePolicy/1.0/nodeslist.json @@ -1,7 +1,7 @@ { "root": { "hostname": "server.rudder.local", - "key-hash": "sha256:", + "key-hash": "sha256:cf621af57886d614617b2c8187d1db9d18c93ee0674c9985fb06fa17705ed4f0", "policy-server": "root" } diff --git a/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/metadata.xml b/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/metadata.xml index fb1350e55f9..b07e7032ecc 100644 --- a/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/metadata.xml +++ b/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/metadata.xml @@ -18,26 +18,28 @@ along with this program. If not, see . System technique for the DSC Agent true - - - rudder-directives.ps1 - - - rudder-system-directives.ps1 - - - - - - rudder.ps1 - false - - - - - - - + + + + rudder-directives.ps1 + + + rudder-system-directives.ps1 + + + + + + rudder.ps1 + false + + + + + + + + RUDDER_DIRECTIVES_SEQUENCE diff --git a/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/rudder-directives.st b/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/rudder-directives.st index 052ab8bef13..7980fbfe300 100644 --- a/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/rudder-directives.st +++ b/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/rudder-directives.st @@ -19,4 +19,9 @@ # This file is the main entry points for the bundle sequence for # Rudder user directives. It is actually a list of method calls. +function Call_Directives( + [string] $class = $null + ) { + &RUDDER_DIRECTIVES_SEQUENCE& +} diff --git a/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/rudder-system-directives.st b/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/rudder-system-directives.st new file mode 100644 index 00000000000..b47d238332e --- /dev/null +++ b/rudder-core/src/test/resources/configuration-repository/techniques/dsc-agent/dsc-agent/1.0/rudder-system-directives.st @@ -0,0 +1,39 @@ +##################################################################################### +# Copyright 2017 Normation SAS +##################################################################################### +# +# This program 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, Version 3. +# +# This program 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 this program. If not, see . +# +##################################################################################### + +# This file is the main entry points for the bundle sequence for +# Rudder system directives. It is actually a list of method calls. + +function Call_System_Directives( + [string] $class = $null + ) { + $system_techniques_path = "$rudder_path\system-techniques" + + Write-Verbose ("Loading all system techniques scripts in $system_techniques_path") + + # Get list of all files in ncf folders, and load them + $system_techniques_files = Get-ChildItem -recurse $system_techniques_path -Filter *.ps1 + + $system_techniques_files | ForEach { + . $_.FullName + } + + Write-Verbose ("Loaded all system technique ps1 scripts") + +&RUDDER_SYSTEM_DIRECTIVES_SEQUENCE& +} diff --git a/rudder-core/src/test/resources/configuration-repository/techniques/ncf_techniques/Create_file/1.0/metadata.xml b/rudder-core/src/test/resources/configuration-repository/techniques/ncf_techniques/Create_file/1.0/metadata.xml index 3bd36ec304b..95b2db54a29 100644 --- a/rudder-core/src/test/resources/configuration-repository/techniques/ncf_techniques/Create_file/1.0/metadata.xml +++ b/rudder-core/src/test/resources/configuration-repository/techniques/ncf_techniques/Create_file/1.0/metadata.xml @@ -2,8 +2,10 @@ Create a file and a directory Create_file - Create_file_rudder_reporting + Create_file_rudder_reporting + + diff --git a/rudder-core/src/test/scala/com/normation/cfclerk/domain/TechniqueTest.scala b/rudder-core/src/test/scala/com/normation/cfclerk/domain/TechniqueTest.scala index e6207789a65..918190d35b3 100644 --- a/rudder-core/src/test/scala/com/normation/cfclerk/domain/TechniqueTest.scala +++ b/rudder-core/src/test/scala/com/normation/cfclerk/domain/TechniqueTest.scala @@ -93,25 +93,29 @@ class TechniqueTest extends Specification { } "have bundle list: 'bundle1,bundle2'" in { - technique.bundlesequence.map( _.name ) === Seq("bundle1","bundle2") + technique.agentConfigs.flatMap( _.bundlesequence.map( _.value )) === Seq("bundle1","bundle2") } "have templates 'tml1, tml2, tml3'" in { - technique.templates.map( _.id.name ) === Seq("tml1", "tml2", "tml3") + technique.agentConfigs.flatMap( _.templates.map( _.id.name )) === Seq("tml1", "tml2", "tml3") + } + + def getTemplateByid(technique: Technique, name: String) = { + technique.agentConfigs.head.templates.find( _.id == TechniqueResourceIdByName(technique.id, name)).getOrElse(throw new Exception(s"Test must contain resource '${name}'")) } "'tml1' is included and has default outpath" in { - val tml = technique.templatesMap(TechniqueResourceIdByName(id,"tml1")) + val tml = getTemplateByid(technique, "tml1") tml.included === true and tml.outPath === "foo/1.0/tml1.cf" } "'tml2' is included and has tml2.bar outpath" in { - val tml = technique.templatesMap(TechniqueResourceIdByName(id,"tml2")) + val tml = getTemplateByid(technique, "tml2") tml.included === true and tml.outPath === "tml2.bar" } "'tml3' is not included and has default outpath" in { - val tml = technique.templatesMap(TechniqueResourceIdByName(id,"tml3")) + val tml = getTemplateByid(technique, "tml3") tml.included === false and tml.outPath === "foo/1.0/tml3.cf" } diff --git a/rudder-core/src/test/scala/com/normation/cfclerk/services/DummyTechniqueRepository.scala b/rudder-core/src/test/scala/com/normation/cfclerk/services/DummyTechniqueRepository.scala index 58680ffe299..e9f7cee0153 100644 --- a/rudder-core/src/test/scala/com/normation/cfclerk/services/DummyTechniqueRepository.scala +++ b/rudder-core/src/test/scala/com/normation/cfclerk/services/DummyTechniqueRepository.scala @@ -38,26 +38,29 @@ package com.normation.cfclerk.services import com.normation.cfclerk.domain._ -import java.io.{ InputStream, File } +import java.io.InputStream import net.liftweb.common._ import scala.collection.SortedSet +import com.normation.inventory.domain.AgentType class DummyTechniqueRepository(policies: Seq[Technique] = Seq()) extends TechniqueRepository { + def agentCfg(bundle: String) = AgentConfig(AgentType.CfeCommunity, Seq(), Seq(), Seq(BundleName(bundle))) :: Nil + var returnedVariable = collection.mutable.Set[VariableSpec]() - val policy1 = Technique(TechniqueId(TechniqueName("policy1"), TechniqueVersion("1.0")), "policy1", "", Seq(), Seq(), Seq(Bundle("one")), TrackerVariableSpec(), SectionSpec(name="root", children=Seq(InputVariableSpec("$variable1", "a variable1"))), None) + val policy1 = Technique(TechniqueId(TechniqueName("policy1"), TechniqueVersion("1.0")), "policy1", "", agentCfg("one"), TrackerVariableSpec(), SectionSpec(name="root", children=Seq(InputVariableSpec("$variable1", "a variable1"))), None) val sections = SectionSpec(name="root", children=Seq(InputVariableSpec("$variable2", "a variable2", multivalued = true), InputVariableSpec("$variable22", "a variable22"))) - val policy2 = Technique(TechniqueId(TechniqueName("policy2"), TechniqueVersion("1.0")), "policy2", "", Seq(), Seq(), Seq(Bundle("two")), TrackerVariableSpec(), sections, None) + val policy2 = Technique(TechniqueId(TechniqueName("policy2"), TechniqueVersion("1.0")), "policy2", "", agentCfg("two"), TrackerVariableSpec(), sections, None) val sections3 = SectionSpec(name="root", children=Seq(InputVariableSpec("$variable3", "a variable3"))) - val policy3 = Technique(TechniqueId(TechniqueName("policy3"), TechniqueVersion("1.0")), "policy3", "", Seq(), Seq(), Seq(Bundle("three")), TrackerVariableSpec(), sections3, None) + val policy3 = Technique(TechniqueId(TechniqueName("policy3"), TechniqueVersion("1.0")), "policy3", "", agentCfg("three"), TrackerVariableSpec(), sections3, None) val sections4 = SectionSpec(name="root", children=Seq(InputVariableSpec("$variable4", "an variable4"))) - val policy4 = Technique(TechniqueId(TechniqueName("policy4"), TechniqueVersion("1.0")), "policy4", "", Seq(), Seq(), Seq(Bundle("four")), TrackerVariableSpec(), sections4, None) + val policy4 = Technique(TechniqueId(TechniqueName("policy4"), TechniqueVersion("1.0")), "policy4", "", agentCfg("four"), TrackerVariableSpec(), sections4, None) val sectionsFoo = SectionSpec(name="root", children=Seq(InputVariableSpec("$bar", "bar"))) - val foo = Technique(TechniqueId(TechniqueName("foo"), TechniqueVersion("1.0")), "foo", "", Seq(), Seq(), Seq(Bundle("foo")), TrackerVariableSpec(), sectionsFoo, None) + val foo = Technique(TechniqueId(TechniqueName("foo"), TechniqueVersion("1.0")), "foo", "", agentCfg("foo"), TrackerVariableSpec(), sectionsFoo, None) val policyMap = Map(policy1.id -> policy1, policy2.id -> policy2, diff --git a/rudder-core/src/test/scala/com/normation/cfclerk/services/JGitPackageReaderTest.scala b/rudder-core/src/test/scala/com/normation/cfclerk/services/JGitPackageReaderTest.scala index af144935bf1..c606a86497f 100644 --- a/rudder-core/src/test/scala/com/normation/cfclerk/services/JGitPackageReaderTest.scala +++ b/rudder-core/src/test/scala/com/normation/cfclerk/services/JGitPackageReaderTest.scala @@ -188,7 +188,7 @@ trait JGitPackageReaderSpec extends Specification with Loggable with AfterAll { "...and version 2.0" in techniques(1).version === TechniqueVersion("2.0") ".... that DOES NOT provide expected_reports.csv" in infos.techniques(techniques(1).name)(techniques(1).version).providesExpectedReports === false "...with 3 templates" in { - infos.techniques(techniques(0).name)(techniques(0).version).templates.toSet === Set( + infos.techniques(techniques(0).name)(techniques(0).version).agentConfigs(0).templates.toSet === Set( TechniqueTemplate(tmlId, s"p1_1/1.0/${tmlId.name}.cf", true) , TechniqueTemplate(templateId, s"bob.txt", false) , TechniqueTemplate(template2Id, s"p1_1/1.0/${template2Id.name}.cf", true) @@ -204,7 +204,7 @@ trait JGitPackageReaderSpec extends Specification with Loggable with AfterAll { assertResourceContent(template2Id, true, template2Content) } "...with 2 files" in { - infos.techniques(techniques(0).name)(techniques(0).version).files.toSet === Set( + infos.techniques(techniques(0).name)(techniques(0).version).agentConfigs(0).files.toSet === Set( TechniqueFile(file1, s"p1_1/1.0/${file1.name}", false) , TechniqueFile(file2, s"file2", false) ) diff --git a/rudder-core/src/test/scala/com/normation/rudder/services/policies/NodeConfigData.scala b/rudder-core/src/test/scala/com/normation/rudder/services/policies/NodeConfigData.scala index 6e7c8554925..a4f10e9771f 100644 --- a/rudder-core/src/test/scala/com/normation/rudder/services/policies/NodeConfigData.scala +++ b/rudder-core/src/test/scala/com/normation/rudder/services/policies/NodeConfigData.scala @@ -96,7 +96,8 @@ import scala.collection.SortedMap import scala.language.implicitConversions import com.normation.inventory.domain.Windows import com.normation.inventory.domain.Windows2012 -import com.normation.inventory.domain.DSC_AGENT +import com.normation.inventory.domain.AgentType +import com.normation.inventory.domain.Certificate /* * This file is a container for testing data that are a little boring to @@ -105,6 +106,18 @@ import com.normation.inventory.domain.DSC_AGENT */ object NodeConfigData { + //a valid, not used pub key + //cfengine key hash is: 081cf3aac62624ebbc83be7e23cb104d + val PUBKEY = +"""-----BEGIN RSA PUBLIC KEY----- +MIIBCAKCAQEAlntroa72gD50MehPoyp6mRS5fzZpsZEHu42vq9KKxbqSsjfUmxnT +Rsi8CDvBt7DApIc7W1g0eJ6AsOfV7CEh3ooiyL/fC9SGATyDg5TjYPJZn3MPUktg +YBzTd1MMyZL6zcLmIpQBH6XHkH7Do/RxFRtaSyicLxiO3H3wapH20TnkUvEpV5Qh +zUkNM8vHZuu3m1FgLrK5NCN7BtoGWgeyVJvBMbWww5hS15IkCRuBkAOK/+h8xe2f +hMQjrt9gW2qJpxZyFoPuMsWFIaX4wrN7Y8ZiN37U2q1G11tv2oQlJTQeiYaUnTX4 +z5VEb9yx2KikbWyChM1Akp82AV5BzqE80QIBIw== +-----END RSA PUBLIC KEY-----""" + val emptyNodeReportingConfiguration = ReportingConfiguration(None,None) val id1 = NodeId("node1") @@ -136,7 +149,7 @@ object NodeConfigData { , List("127.0.0.1", "192.168.0.100") , DateTime.now , UndefinedKey - , Seq(AgentInfo(CfeCommunity, Some(AgentVersion("4.0.0")), PublicKey("test"))) + , Seq(AgentInfo(CfeCommunity, Some(AgentVersion("4.0.0")), PublicKey(PUBKEY))) , rootId , rootAdmin , Set( //by default server roles for root @@ -175,7 +188,7 @@ object NodeConfigData { , List("192.168.0.10") , DateTime.now , UndefinedKey - , Seq(AgentInfo(CfeCommunity, Some(AgentVersion("4.0.0")), PublicKey("test"))) + , Seq(AgentInfo(CfeCommunity, Some(AgentVersion("4.0.0")), PublicKey(PUBKEY))) , rootId , admin1 , Set() @@ -240,8 +253,8 @@ object NodeConfigData { , Windows(Windows2012, "Windows 2012 youpla boom", new Version("2012"), Some("sp1"), new Version("win-kernel-2012")) , List("192.168.0.5") , DateTime.now - , None, UndefinedKey - , Seq(AgentInfo(DSC_AGENT, Some(AgentVersion("5.0.0")))) + , UndefinedKey + , Seq(AgentInfo(AgentType.Dsc, Some(AgentVersion("5.0.0")), Certificate("windows-node-dsc-certificate"))) , rootId , admin1 , Set() @@ -270,7 +283,6 @@ object NodeConfigData { , lastLoggedUser = None , lastLoggedUserTime = None , agents = Seq() - , publicKeys = Seq() , serverIps = Seq() , machineId = None //if we want several ids, we would have to ass an "alternate machine" field , softwareIds = Seq() @@ -394,7 +406,7 @@ object NodeConfigData { implicit def toDID(id: String) = DirectiveId(id) implicit def toRID(id: String) = RuleId(id) implicit def toRCID(id: String) = RuleCategoryId(id) - val t1 = Technique(("t1", "1.0"), "t1", "t1", Seq(), Seq(), Seq(), TrackerVariableSpec(), SectionSpec("root"), None) + val t1 = Technique(("t1", "1.0"), "t1", "t1", Nil, TrackerVariableSpec(), SectionSpec("root"), None) val d1 = Directive("d1", "1.0", Map("foo1" -> Seq("bar1")), "d1", "d1", None) val d2 = Directive("d2", "1.0", Map("foo2" -> Seq("bar2")), "d2", "d2", Some(PolicyMode.Enforce)) val d3 = Directive("d3", "1.0", Map("foo3" -> Seq("bar3")), "d3", "d3", Some(PolicyMode.Audit)) diff --git a/rudder-core/src/test/scala/com/normation/rudder/services/policies/RuleValServiceTest.scala b/rudder-core/src/test/scala/com/normation/rudder/services/policies/RuleValServiceTest.scala index c3db5e712f2..10fd2ea32e3 100644 --- a/rudder-core/src/test/scala/com/normation/rudder/services/policies/RuleValServiceTest.scala +++ b/rudder-core/src/test/scala/com/normation/rudder/services/policies/RuleValServiceTest.scala @@ -116,9 +116,7 @@ class RuleValServiceTest extends Specification { id , "meta" + id , "" - , Seq() - , Seq() - , Seq() + , Nil , TrackerVariableSpec(None) , makeRootSectionSpec , None diff --git a/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PolicyInstanceAgregationTest.scala b/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PolicyInstanceAgregationTest.scala index dddeaa0e28a..be7e873301f 100644 --- a/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PolicyInstanceAgregationTest.scala +++ b/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PolicyInstanceAgregationTest.scala @@ -81,9 +81,7 @@ class DirectiveAgregationTest { activeTechniqueId1 , "name" , "DESCRIPTION" - , Seq() - , Seq() - , Seq() + , Nil , trackerVariableSpec , SectionSpec(name="root", children=Seq()) , None @@ -93,9 +91,7 @@ class DirectiveAgregationTest { activeTechniqueId2 , "name" , "DESCRIPTION" - , Seq() - , Seq() - , Seq() + , Nil , trackerVariableSpec , SectionSpec(name="root", children=Seq()) , None @@ -172,7 +168,7 @@ class DirectiveAgregationTest { def arrayedDirectiveTest() { val newTechniqueId = TechniqueId(TechniqueName("name"), TechniqueVersion("1.0")) - def newTechnique = Technique(newTechniqueId, "tech" + newTechniqueId, "", Seq(), Seq(), Seq(), TrackerVariableSpec(), SectionSpec("plop"), None, Set(), None) + def newTechnique = Technique(newTechniqueId, "tech" + newTechniqueId, "", Nil, TrackerVariableSpec(), SectionSpec("plop"), None, Set(), None) val instance = new Cf3PolicyDraft("id", newTechnique, DateTime.now, Map(), trackerVariable, priority = 0, serial = 0, ruleOrder = BundleOrder("r"), directiveOrder = BundleOrder("d"), overrides = Set(), policyMode = None, isSystem = false) diff --git a/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariableTest.scala b/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariableTest.scala index 951e13b719e..9412401f03e 100644 --- a/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariableTest.scala +++ b/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/PrepareTemplateVariableTest.scala @@ -40,18 +40,18 @@ import org.junit.runner._ import org.specs2.mutable._ import org.specs2.runner._ import com.normation.rudder.services.policies.write.BuildBundleSequence._ -import com.normation.cfclerk.domain.Bundle +import com.normation.cfclerk.domain.BundleName import com.normation.rudder.domain.policies.PolicyMode @RunWith(classOf[JUnitRunner]) class PrepareTemplateVariableTest extends Specification { val bundles = Seq( - ("Global configuration for all nodes/20. Install jdk version 1.0" , Bundle("Install_jdk_rudder_reporting")) - , ("Global configuration for all nodes/RUG / YaST package manager configuration (ZMD)", Bundle("check_zmd_settings")) - , ("""Nodes only/Name resolution version "3.0" and counting""" , Bundle("check_dns_configuration")) - , (raw"""Nodes only/Package \"management\" for Debian""" , Bundle("check_apt_package_installation")) - , (raw"""Nodes only/Package \\"management\\" for Debian - again""" , Bundle("check_apt_package_installation2")) + ("Global configuration for all nodes/20. Install jdk version 1.0" , Bundle(ReportId("not used"), BundleName("Install_jdk_rudder_reporting"))) + , ("Global configuration for all nodes/RUG / YaST package manager configuration (ZMD)", Bundle(ReportId("not used"), BundleName("check_zmd_settings"))) + , ("""Nodes only/Name resolution version "3.0" and counting""" , Bundle(ReportId("not used"), BundleName("check_dns_configuration"))) + , (raw"""Nodes only/Package \"management\" for Debian""" , Bundle(ReportId("not used"), BundleName("check_apt_package_installation"))) + , (raw"""Nodes only/Package \\"management\\" for Debian - again""" , Bundle(ReportId("not used"), BundleName("check_apt_package_installation2"))) ).map { case(x,y) => TechniqueBundles(Directive(x), Nil, y::Nil, Nil, false, false, PolicyMode.Enforce) } // Ok, now I can test diff --git a/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/WriteSystemTechniquesTest.scala b/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/WriteSystemTechniquesTest.scala index 679c161e774..83bbd21844d 100644 --- a/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/WriteSystemTechniquesTest.scala +++ b/rudder-core/src/test/scala/com/normation/rudder/services/policies/write/WriteSystemTechniquesTest.scala @@ -111,6 +111,14 @@ import com.normation.cfclerk.domain.Variable @RunWith(classOf[JUnitRunner]) class WriteSystemTechniquesTest extends Specification with Loggable with BoxSpecMatcher with ContentMatchers with AfterAll { + //make tests more similar than default rudder install + val hookIgnore = """.swp, ~, .bak, + .cfnew , .cfsaved , .cfedited, .cfdisabled, .cfmoved, + .dpkg-old, .dpkg-dist, .dpkg-new, .dpkg-tmp, + .disable , .disabled , _disable , _disabled, + .ucf-old , .ucf-dist , .ucf-new , + .rpmnew , .rpmsave , .rpmorig""".split(",").map( _.trim).toList + //just a little sugar to stop hurting my eyes with new File(blablab, plop) implicit class PathString(root: String) { def /(child: String) = new File(root, child) @@ -222,8 +230,8 @@ class WriteSystemTechniquesTest extends Specification with Loggable with BoxSpec , logNodeConfig , prepareTemplateVariable , new FillTemplatesService() - , "/opt/rudder/etc/hooks.d" - , Nil + , "/we-don-t-want-hooks-here" + , hookIgnore ) (rootGeneratedPromisesDir, promiseWritter)