From 5973753c26b1a3d0bb454b0e9f3dc1aaac62fadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vincent=20Membr=C3=A9?= Date: Wed, 31 Aug 2016 16:48:54 +0200 Subject: [PATCH] Work in progress --- .../src/main/resources/ldap/rudder.schema | 13 +- .../rudder/domain/RudderLDAPConstants.scala | 5 +- .../domain/eventlog/EventLogCategories.scala | 9 +- .../eventlog/ModifyGlobalProperty.scala | 2 +- .../normation/rudder/domain/nodes/Node.scala | 4 + .../rudder/domain/policies/Directive.scala | 118 +++++++++--------- .../rudder/policyMode/PolicyMode.scala | 83 ++++++++++++ .../repository/ldap/LDAPEntityMapper.scala | 26 +++- .../marshalling/XmlUnserialisationImpl.scala | 17 +-- .../services/servers/NewNodeManager.scala | 20 +-- .../domain/policies/RuleTargetTest.scala | 3 +- .../services/policies/NodeConfigData.scala | 3 + .../policies/RuleValServiceTest.scala | 2 + .../rudder/appconfig/ConfigService.scala | 49 +++++++- .../popup/CreateCloneDirectivePopup.scala | 18 +-- .../rest/directive/DirectiveAPIService2.scala | 3 +- .../configuration/DirectiveManagement.scala | 2 + 17 files changed, 266 insertions(+), 111 deletions(-) create mode 100644 rudder-core/src/main/scala/com/normation/rudder/policyMode/PolicyMode.scala diff --git a/rudder-core/src/main/resources/ldap/rudder.schema b/rudder-core/src/main/resources/ldap/rudder.schema index a420a675840..0c4ae2e884b 100644 --- a/rudder-core/src/main/resources/ldap/rudder.schema +++ b/rudder-core/src/main/resources/ldap/rudder.schema @@ -316,6 +316,14 @@ attributetype ( RudderAttributes:230 EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{4096} ) + +### Policy mode, common for Nodes/Directive at first, Surely Rules and groups later +attributetype ( RudderAttributes:231 + NAME 'policyMode' + DESC 'Policy mode (Enforce/Verify) for this element ' + SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 + EQUALITY caseIgnoreMatch + SUBSTR caseIgnoreSubstringsMatch ) ### API principal and tokens @@ -416,7 +424,8 @@ objectclass ( RudderObjectClasses:1 SUP top STRUCTURAL MUST ( nodeId $ cn $ isSystem $ isBroken) - MAY ( description $ serializedNodeProperty $ serializedAgentRunInterval $ serializedHeartbeatRunConfiguration ) ) + MAY ( description $ serializedNodeProperty $ serializedAgentRunInterval $ + serializedHeartbeatRunConfiguration $ policyMode ) ) objectclass ( RudderObjectClasses:2 NAME 'rudderPolicyServer' @@ -484,7 +493,7 @@ objectclass ( RudderObjectClasses:23 STRUCTURAL MUST ( directiveId $ techniqueVersion ) MAY ( cn $ description $ longDescription $ isEnabled $ isSystem $ - directivePriority $ directiveVariable ) ) + directivePriority $ directiveVariable $ policyMode ) ) ### rules ### diff --git a/rudder-core/src/main/scala/com/normation/rudder/domain/RudderLDAPConstants.scala b/rudder-core/src/main/scala/com/normation/rudder/domain/RudderLDAPConstants.scala index b2651512176..08c3d36a9d4 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/domain/RudderLDAPConstants.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/domain/RudderLDAPConstants.scala @@ -90,10 +90,10 @@ object RudderLDAPConstants extends Loggable { val A_SERIALIZED_AGENT_RUN_INTERVAL = "serializedAgentRunInterval" val A_SERIALIZED_HEARTBEAT_RUN_CONFIGURATION = "serializedHeartbeatRunConfiguration" + val A_POLICY_MODE = "policyMode" val A_NODE_PROPERTY = "serializedNodeProperty" - val A_PRIORITY = "directivePriority" val A_LONG_DESCRIPTION = "longDescription" val A_SERIAL = "serial" @@ -110,7 +110,6 @@ object RudderLDAPConstants extends Loggable { val A_TARGET_AGENTS_NAME = "targetAgentName" val A_TARGET_ROOT_USER = "targetLocalAdministratorAccountName" - // Creation date of an object // it's an operational attribute of OpenLDAP val A_OBJECT_CREATION_DATE = "createTimestamp" @@ -225,7 +224,6 @@ object RudderLDAPConstants extends Loggable { OC += (OC_ACTIVE_TECHNIQUE_LIB_VERSION, may = Set(A_INIT_DATETIME)) - OC += (OC_API_ACCOUNT , must = Set(A_API_UUID, A_NAME, A_CREATION_DATETIME, A_API_TOKEN, A_API_TOKEN_CREATION_DATETIME) , may = Set(A_DESCRIPTION) @@ -243,7 +241,6 @@ object RudderLDAPConstants extends Loggable { must = Set(A_NAME), may = Set(A_DESCRIPTION, A_NODE_CONFIG)) - /** * Serialize and unserialize variables in A_DIRECTIVE_VARIABLES */ diff --git a/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/EventLogCategories.scala b/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/EventLogCategories.scala index 37614a8b1a2..f60a154e048 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/EventLogCategories.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/EventLogCategories.scala @@ -59,7 +59,6 @@ final case object GlobalPropertyEventLogCategory extends EventLogCategory final case object SettingsLogCategory extends EventLogCategory final case object NodeLogCategory extends EventLogCategory - // the promises related event type final case object AutomaticStartDeployementEventType extends NoRollbackEventLogType { def serialize = "AutomaticStartDeployement" @@ -228,8 +227,6 @@ final case object ModifyGlobalParameterEventType extends RollbackEventLogType { def serialize = "GlobalParameterModified" } - - // node properties: properties, heartbeat, agent run. final case object ModifyHeartbeatNodeEventType extends RollbackEventLogType { def serialize = "NodeHeartbeatModified" @@ -287,6 +284,11 @@ final case object ModifyRudderSyslogProtocolEventType extends ModifyGlobalProper val propertyName = "Rudder syslog protocol" } +final case object ModifyPolicyModeEventType extends ModifyGlobalPropertyEventType { + def serialize = "PolicyModeModified" + val propertyName = "Global policy mode" +} + /** * List of event generating a modification of promises */ @@ -327,7 +329,6 @@ object ModificationWatchList { } - object EventTypeFactory { val eventTypes = List[EventLogType]( AutomaticStartDeployementEventType diff --git a/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/ModifyGlobalProperty.scala b/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/ModifyGlobalProperty.scala index 489404af179..436fa30c9b5 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/ModifyGlobalProperty.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/domain/eventlog/ModifyGlobalProperty.scala @@ -3,7 +3,6 @@ package com.normation.rudder.domain.eventlog import com.normation.eventlog._ import com.normation.utils.HashcodeCaching - case class ModifyGlobalProperty( eventType: ModifyGlobalPropertyEventType , eventDetails : EventLogDetails @@ -30,6 +29,7 @@ object ModifyGlobalPropertyEventLogsFilter { ModifyAgentRunStartHourEventType :: ModifyAgentRunStartMinuteEventType :: ModifyRudderSyslogProtocolEventType :: + ModifyPolicyModeEventType :: Nil final val eventList : List[EventLogFilter] = diff --git a/rudder-core/src/main/scala/com/normation/rudder/domain/nodes/Node.scala b/rudder-core/src/main/scala/com/normation/rudder/domain/nodes/Node.scala index fbc5361a226..3ab409b1c27 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/domain/nodes/Node.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/domain/nodes/Node.scala @@ -46,6 +46,8 @@ import com.normation.rudder.reports.AgentRunInterval import com.normation.rudder.reports.HeartbeatConfiguration import com.normation.rudder.domain.policies.SimpleDiff import com.normation.inventory.domain.FullInventory +import com.normation.rudder.policyMode.PolicyMode +import com.normation.rudder.policyMode.Enforce /** * The entry point for a REGISTERED node in Rudder. @@ -63,6 +65,7 @@ case class Node( , creationDate : DateTime , nodeReportingConfiguration: ReportingConfiguration , properties : Seq[NodeProperty] + , policyMode : Option[PolicyMode] ) extends HashcodeCaching case object Node { @@ -77,6 +80,7 @@ case object Node { , inventory.node.inventoryDate.getOrElse(new DateTime(0)) , ReportingConfiguration(None,None) , Seq() + , None ) } } diff --git a/rudder-core/src/main/scala/com/normation/rudder/domain/policies/Directive.scala b/rudder-core/src/main/scala/com/normation/rudder/domain/policies/Directive.scala index d3e286f2df2..1f8c45ecdc5 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/domain/policies/Directive.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/domain/policies/Directive.scala @@ -44,8 +44,9 @@ import com.normation.cfclerk.domain.TechniqueVersion import com.normation.utils.HashcodeCaching import com.normation.cfclerk.domain.SectionSpec import com.normation.cfclerk.domain.Technique +import com.normation.rudder.policyMode.PolicyMode -case class DirectiveId(value:String) extends HashcodeCaching +case class DirectiveId(value : String) extends HashcodeCaching /** * Define a directive. @@ -64,61 +65,54 @@ case class DirectiveId(value:String) extends HashcodeCaching * the same technique. * */ -case class Directive( - id:DirectiveId, - - //TODO: why not keeping techniqueName here ? data duplication ? - - /** - * 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]], - - /** - * 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, - - /** - * Short description, typically used as field description - * Can not be empty nor null. - */ - shortDescription:String, - - /** - * A long, detailed description, typically used for - * tooltip. It allows reach content. - * Can be empty (and is by default). - */ - 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, - - /** - * 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, + //TODO: why not keeping techniqueName here ? data duplication ? - isSystem:Boolean = false +case class Directive( + 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]] + /** + * 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 + /** + * Short description, typically used as field description + * Can not be empty nor null. + */ + , shortDescription : String + , policyMode : Option[PolicyMode] + /** + * A long, detailed description, typically used for + * tooltip. It allows reach content. + * Can be empty (and is by default). + */ + , 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 + /** + * 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 ) extends HashcodeCaching { //system object must ALWAYS be ENABLED. def isEnabled = _isEnabled || isSystem @@ -132,7 +126,7 @@ final case class SectionVal( object SectionVal { val ROOT_SECTION_NAME = "sections" - def toXml(sv:SectionVal, sectionName:String = ROOT_SECTION_NAME): Node = { + def toXml(sv : SectionVal, sectionName : String = ROOT_SECTION_NAME): Node = {
{ //variables sv.variables.toSeq.sortBy(_._1).map { case (variable,value) => @@ -149,11 +143,11 @@ object SectionVal {
} - def directiveValToSectionVal(rootSection:SectionSpec, allValues:Map[String,Seq[String]]) : SectionVal = { + def directiveValToSectionVal(rootSection : SectionSpec, allValues : Map[String,Seq[String]]) : SectionVal = { /* * build variables with a parent section multivalued. */ - def buildMonoSectionWithMultivaluedParent(spec:SectionSpec, index:Int) : SectionVal = { + def buildMonoSectionWithMultivaluedParent(spec : SectionSpec, index : Int) : SectionVal = { if(spec.isMultivalued) throw new RuntimeException("We found a multivalued subsection of a multivalued section: " + spec) //variable for that section: Map[String, String] @@ -172,7 +166,7 @@ object SectionVal { } - def buildMultiSectionWithoutMultiParent(spec:SectionSpec) : Seq[SectionVal] = { + def buildMultiSectionWithoutMultiParent(spec : SectionSpec) : Seq[SectionVal] = { if(!spec.isMultivalued) throw new RuntimeException("We found a monovalued section where a multivalued section was asked for: " + spec) // find the number of iteration for that multivalued section. @@ -224,7 +218,7 @@ object SectionVal { } } - def buildMonoSectionWithoutMultivaluedParent(spec:SectionSpec) : SectionVal = { + def buildMonoSectionWithoutMultivaluedParent(spec : SectionSpec) : SectionVal = { val variables = spec.getDirectVariables.map { vspec => //we can have a empty value for a variable, for non mandatory ones (vspec.name, allValues.getOrElse(vspec.name,Seq(""))(0)) @@ -244,11 +238,11 @@ object SectionVal { buildMonoSectionWithoutMultivaluedParent(rootSection) } - def toMapVariables(sv:SectionVal) : Map[String,Seq[String]] = { + def toMapVariables(sv : SectionVal) : Map[String,Seq[String]] = { import scala.collection.mutable.{Map, Buffer} val res = Map[String, Buffer[String]]() - def recToMap(sec:SectionVal) : Unit = { + def recToMap(sec : SectionVal) : Unit = { sec.variables.foreach { case (name,value) => res.getOrElseUpdate(name, Buffer()).append(value) } diff --git a/rudder-core/src/main/scala/com/normation/rudder/policyMode/PolicyMode.scala b/rudder-core/src/main/scala/com/normation/rudder/policyMode/PolicyMode.scala new file mode 100644 index 00000000000..a7425fd5ee4 --- /dev/null +++ b/rudder-core/src/main/scala/com/normation/rudder/policyMode/PolicyMode.scala @@ -0,0 +1,83 @@ +/* +************************************************************************************* +* 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 . + +* +************************************************************************************* +*/ +package com.normation.rudder.policyMode + +import net.liftweb.common.{Box,Full,Failure} + +sealed trait PolicyMode { + def name : String +} + +case object Verify extends PolicyMode { + val name = "verify" +} + +case object Enforce extends PolicyMode { + val name = "enforce" +} + +object PolicyModeName { + val allModes : List[PolicyMode] = Verify :: Enforce :: Nil + + def parse (value : String) : Box[PolicyMode] = { + allModes.find { _.name == value } match { + case None => + Failure(s"Unable to parse policy mode name '${value}'. was expecting ${allModes.map(_.name).mkString("'", "' or '", "'")}.") + case Some(mode) => + Full(mode) + } + } +} + +case class GlobalPolicyMode ( + mode : PolicyMode + , overridable : Boolean +) + +object PolicyModeService { + + def computeMode(globalValue : GlobalPolicyMode, nodeMode : Option[PolicyMode], directiveMode : Option[PolicyMode]) = { + if (globalValue.overridable) { + nodeMode match { + case Some(Verify) => Verify + case _ => directiveMode.getOrElse(globalValue.mode) + } + } else { + globalValue.mode + } + } +} diff --git a/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPEntityMapper.scala b/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPEntityMapper.scala index b811f2354bf..c18fe6b40bf 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPEntityMapper.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPEntityMapper.scala @@ -80,6 +80,8 @@ import net.liftweb.json._ import JsonDSL._ import com.normation.rudder.reports._ import com.normation.inventory.ldap.core.InventoryMapper +import com.normation.rudder.policyMode.PolicyModeName +import com.normation.rudder.policyMode.Enforce /** * Map objects from/to LDAPEntries @@ -124,6 +126,11 @@ class LDAPEntityMapper( entry +=! (A_SERIALIZED_HEARTBEAT_RUN_CONFIGURATION, Printer.compact(JsonAST.render(json))) case _ => // Save nothing if missing } + + for { + mode <- node.policyMode + } entry += (A_POLICY_MODE, mode.name) + entry } @@ -158,6 +165,7 @@ class LDAPEntityMapper( date <- e.getAsGTime(A_OBJECT_CREATION_DATE) ?~! s"Can not find mandatory attribute '${A_OBJECT_CREATION_DATE}' in entry" agentRunInterval = e(A_SERIALIZED_AGENT_RUN_INTERVAL).map(unserializeAgentRunInterval(_)) heartbeatConf = e(A_SERIALIZED_HEARTBEAT_RUN_CONFIGURATION).map(unserializeNodeHeartbeatConfiguration(_)) + policyMode <- e(A_POLICY_MODE).map(PolicyModeName.parse(_)) } yield { Node( id @@ -172,6 +180,7 @@ class LDAPEntityMapper( , heartbeatConf ) , e.valuesFor(A_NODE_PROPERTY).map(unserializeLdapNodeProperty(_)).toSeq + , policyMode ) } } else { @@ -217,6 +226,7 @@ class LDAPEntityMapper( , new DateTime(0) // we don't know anymore the acceptation date , ReportingConfiguration(None, None) //we don't know anymore agent run frequency , Seq() //we forgot node properties + , None ) nodeInfo <- inventoryEntriesToNodeInfos(node, inventoryEntry, machineEntry) } yield { @@ -527,6 +537,7 @@ class LDAPEntityMapper( for { id <- e(A_DIRECTIVE_UUID) ?~! "Missing required attribute %s in entry %s".format(A_DIRECTIVE_UUID, e) s_version <- e(A_TECHNIQUE_VERSION) ?~! "Missing required attribute %s in entry %s".format(A_TECHNIQUE_VERSION, e) + policyMode <- e(A_POLICY_MODE).map(PolicyModeName.parse(_)) version <- tryo(TechniqueVersion(s_version)) name = e(A_NAME).getOrElse(id) params = parsePolicyVariables(e.valuesFor(A_DIRECTIVE_VARIABLES).toSeq) @@ -537,8 +548,16 @@ class LDAPEntityMapper( isSystem = e.getAsBoolean(A_IS_SYSTEM).getOrElse(false) } yield { Directive( - DirectiveId(id), version, params, name, - shortDescription,longDescription,priority, isEnabled, isSystem + DirectiveId(id) + , version + , params + , name + , shortDescription + , policyMode + , longDescription + , priority + , isEnabled + , isSystem ) } } else Failure("The given entry is not of the expected ObjectClass '%s'. Entry details: %s".format(OC_DIRECTIVE, e)) @@ -558,6 +577,9 @@ class LDAPEntityMapper( entry +=! (A_PRIORITY, directive.priority.toString) entry +=! (A_IS_ENABLED, directive.isEnabled.toLDAPString) entry +=! (A_IS_SYSTEM, directive.isSystem.toLDAPString) + for { + mode <- directive.policyMode + } entry +=! (A_POLICY_MODE, mode.name) entry } diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala b/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala index a597d6ba027..1f45e1375ac 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/marshalling/XmlUnserialisationImpl.scala @@ -94,6 +94,7 @@ import scala.xml.XML import scala.xml.PrettyPrinter import com.normation.rudder.rule.category.RuleCategory import com.normation.rudder.rule.category.RuleCategoryId +import com.normation.rudder.policyMode.PolicyModeName case class XmlUnserializerImpl ( rule : RuleUnserialisation @@ -159,20 +160,22 @@ class DirectiveUnserialisationImpl extends DirectiveUnserialisation { isEnabled <- (directive \ "isEnabled").headOption.flatMap(s => tryo { s.text.toBoolean } ) ?~! ("Missing attribute 'isEnabled' in entry type directive : " + xml) priority <- (directive \ "priority").headOption.flatMap(s => tryo { s.text.toInt } ) ?~! ("Missing or bad attribute 'priority' in entry type directive : " + xml) isSystem <- (directive \ "isSystem").headOption.flatMap(s => tryo { s.text.toBoolean } ) ?~! ("Missing attribute 'isSystem' in entry type directive : " + xml) + policyMode = (directive \ "policyMode").headOption.flatMap(s => PolicyModeName.parse(s.text) ) directiveIds = (directive \ "directiveIds" \ "id" ).map( n => DirectiveId( n.text ) ).toSet } yield { ( TechniqueName(ptName) , Directive( - id = DirectiveId(id) - , name = name + id = DirectiveId(id) + , name = name , techniqueVersion = techniqueVersion - , parameters = SectionVal.toMapVariables(sectionVal) + , parameters = SectionVal.toMapVariables(sectionVal) , shortDescription = shortDescription - , longDescription = longDescription - , priority = priority - , _isEnabled = isEnabled - , isSystem = isSystem + , policyMode = policyMode + , longDescription = longDescription + , priority = priority + , _isEnabled = isEnabled + , isSystem = isSystem ) , sectionVal ) diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/servers/NewNodeManager.scala b/rudder-core/src/main/scala/com/normation/rudder/services/servers/NewNodeManager.scala index 07ed7ceb0c6..295b4db536d 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/servers/NewNodeManager.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/servers/NewNodeManager.scala @@ -72,6 +72,7 @@ import org.apache.commons.net.util.SubnetUtils import com.normation.rudder.domain.eventlog._ import com.normation.rudder.reports._ import com.normation.rudder.repository.EventLogRepository +import com.normation.rudder.policyMode.Enforce /** * A trait to manage the acceptation of new node in Rudder @@ -111,7 +112,6 @@ trait NewNodeManager { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /** * Default implementation: a new server manager composed with a sequence of * "unit" accept, one by main goals of what it means to accept a server; @@ -135,7 +135,6 @@ class NewNodeManagerImpl( /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - trait ListNewNode extends NewNodeManager with Loggable { def ldap:LDAPConnectionProvider[RoLDAPConnection] def serverSummaryService:NodeSummaryServiceImpl @@ -156,7 +155,6 @@ trait ListNewNode extends NewNodeManager with Loggable { } } - trait UnitRefuseInventory { def name : String @@ -222,7 +220,6 @@ trait ComposedNewNodeManager extends NewNodeManager with Loggable { def unitAcceptors:Seq[UnitAcceptInventory] def unitRefusors:Seq[UnitRefuseInventory] - def inventoryHistoryLogRepository : InventoryHistoryLogRepository def eventLogRepository : EventLogRepository @@ -368,7 +365,6 @@ trait ComposedNewNodeManager extends NewNodeManager with Loggable { } } - /** * Accept one server. * Accepting mean that the server went to all unitAccept items and that all of them @@ -397,7 +393,6 @@ trait ComposedNewNodeManager extends NewNodeManager with Loggable { } } - override def accept(id: NodeId, modId: ModificationId, actor:EventActor) : Box[FullInventory] = { // // start by retrieving all sms @@ -427,7 +422,6 @@ trait ComposedNewNodeManager extends NewNodeManager with Loggable { } } - // //now, execute unit acceptor // @@ -444,7 +438,6 @@ trait ComposedNewNodeManager extends NewNodeManager with Loggable { return eb } - // //now, execute global post process // @@ -468,7 +461,6 @@ trait ComposedNewNodeManager extends NewNodeManager with Loggable { } } - override def accept(ids: Seq[NodeId], modId: ModificationId, actor:EventActor, actorIp : String) : Box[Seq[FullInventory]] = { // Get inventory from a nodeId @@ -589,7 +581,6 @@ trait ComposedNewNodeManager extends NewNodeManager with Loggable { } - /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /** @@ -641,7 +632,6 @@ class AcceptInventory( /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - /** * Accept FullInventory at ou=node level: just add it * TODO: use NodeRepository @@ -654,7 +644,6 @@ class AcceptFullInventoryInNodeOu( inventoryStatus:InventoryStatus //expected inventory status of nodes for that processor ) extends UnitAcceptInventory with UnitRefuseInventory with Loggable { - override def preAccept(sms:Seq[FullInventory], modId: ModificationId, actor:EventActor) : Box[Seq[FullInventory]] = Full(sms) //nothing to do override def postAccept(sms:Seq[FullInventory], modId: ModificationId, actor:EventActor) : Box[Seq[FullInventory]] = Full(sms) //nothing to do @@ -684,6 +673,7 @@ class AcceptFullInventoryInNodeOu( , DateTime.now // won't be used on save - dummy value , ReportingConfiguration(None,None) // use global schedule , Seq() //no user properties for now + , None // Default policy mode ) val entry = ldapEntityMapper.nodeToEntry(node) @@ -713,7 +703,6 @@ class AcceptFullInventoryInNodeOu( } } - //////////// refuse //////////// override def refuseOne(srv:Srv, modId: ModificationId, actor:EventActor) : Box[Srv] = { //refuse ou=nodes: delete it @@ -728,7 +717,6 @@ class AcceptFullInventoryInNodeOu( } - class RefuseGroups( override val name:String , roGroupRepo: RoNodeGroupRepository @@ -776,10 +764,6 @@ class AcceptHostnameAndIp( , policyServerNet : PolicyServerManagementService ) extends UnitAcceptInventory { - - - - //return the list of ducplicated hostname from user input - we want that to be empty private[this] def checkDuplicateString(attributes:Seq[String], attributeName:String) : Box[Unit]= { val duplicates = attributes.groupBy( x => x ).collect { case (k,v) if v.size > 1 => v.head }.toSeq.sorted diff --git a/rudder-core/src/test/scala/com/normation/rudder/domain/policies/RuleTargetTest.scala b/rudder-core/src/test/scala/com/normation/rudder/domain/policies/RuleTargetTest.scala index 7602e71a206..083280a2c5d 100644 --- a/rudder-core/src/test/scala/com/normation/rudder/domain/policies/RuleTargetTest.scala +++ b/rudder-core/src/test/scala/com/normation/rudder/domain/policies/RuleTargetTest.scala @@ -19,6 +19,7 @@ import com.normation.inventory.domain.Debian import com.normation.inventory.domain.Linux import com.normation.inventory.domain.Version import com.normation.inventory.domain.UndefinedKey +import com.normation.rudder.policyMode.Enforce @RunWith(classOf[JUnitRunner]) class RuleTargetTest extends Specification with Loggable { @@ -29,7 +30,7 @@ class RuleTargetTest extends Specification with Loggable { NodeId(s"${i}") }).toSet - def newNode(id : NodeId) = Node(id,"" ,"", false, false, false, DateTime.now, ReportingConfiguration(None,None), Seq()) + def newNode(id : NodeId) = Node(id,"" ,"", false, false, false, DateTime.now, ReportingConfiguration(None,None), Seq(), None) val allNodeIds = nodeIds + NodeId("root") val nodes = allNodeIds.map { 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 262c3c19b22..8140c944546 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 @@ -58,6 +58,7 @@ import com.normation.inventory.domain.VirtualMachineType import com.normation.rudder.domain.nodes.MachineInfo import com.normation.inventory.domain.MemorySize import com.normation.inventory.domain.MachineUuid +import com.normation.rudder.policyMode.Enforce /* * This file is a container for testing data that are a little boring to @@ -86,6 +87,7 @@ object NodeConfigData { , DateTime.now , emptyNodeReportingConfiguration , Seq() + , Some(Enforce) ) val root = NodeInfo ( rootNode @@ -122,6 +124,7 @@ object NodeConfigData { , DateTime.now , emptyNodeReportingConfiguration , Seq() + , None ) val node1 = NodeInfo ( 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 5b06a1fc297..18084714ab4 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 @@ -55,6 +55,7 @@ import com.normation.rudder.domain.policies.Rule import com.normation.rudder.domain.policies.GroupTarget import com.normation.rudder.domain.nodes.NodeGroupId import com.normation.rudder.rule.category.RuleCategoryId +import com.normation.rudder.policyMode.Enforce /** * Test how RuleVal and DirectiveVal are constructed, and if they @@ -138,6 +139,7 @@ class RuleValServiceTest extends Specification { , Map() , "MyDirective" , "shortDescription" + , None , "longDescription" , 5 , true diff --git a/rudder-web/src/main/scala/com/normation/rudder/appconfig/ConfigService.scala b/rudder-web/src/main/scala/com/normation/rudder/appconfig/ConfigService.scala index 466a4211632..9da5af94519 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/appconfig/ConfigService.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/appconfig/ConfigService.scala @@ -66,7 +66,7 @@ import scala.language.implicitConversions import ca.mrvisser.sealerate import com.normation.rudder.web.components.popup.ModificationValidationPopup.Disable import com.normation.rudder.domain.appconfig.FeatureSwitch - +import com.normation.rudder.policyMode._ /** * A service that Read mutable (runtime) configuration properties @@ -135,6 +135,21 @@ trait ReadConfigService { def rudder_compliance_heartbeatPeriod(): Box[Int] + /** + * Policy mode: See PolicyMode class for more details + */ + def rudder_global_policy_mode(): Box[GlobalPolicyMode] = { + for { + name <- rudder_policy_mode_name + modeName <- PolicyModeName.parse(name) + overridable <- rudder_policy_overridable + } yield { + GlobalPolicyMode(modeName,overridable) + } + } + def rudder_policy_mode_name(): Box[String] + def rudder_policy_overridable(): Box[Boolean] + /** * Send Metrics */ @@ -246,6 +261,24 @@ trait UpdateConfigService { * Should we evaluate scripts in variable values? */ def set_rudder_featureSwitch_directiveScriptEngine(status: FeatureSwitch): Box[Unit] + +/** + * Set the compliance mode + */ + def set_rudder_policy_mode(mode : GlobalPolicyMode, actor: EventActor, reason: Option[String]): Box[Unit] = { + for { + _ <- set_rudder_policy_mode_name(mode.mode, actor, reason) + u <- set_rudder_policy_overridable(mode.overridable, actor, reason) + } yield { + u + } + + } + + def set_rudder_policy_mode_name(name : PolicyMode, actor : EventActor, reason: Option[String]) : Box[Unit] + + def set_rudder_policy_overridable(overridable : Boolean, actor: EventActor, reason: Option[String]) : Box[Unit] + } class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workflowUpdate: AsyncWorkflowInfo) extends ReadConfigService with UpdateConfigService with Loggable { @@ -278,6 +311,8 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl display.changes.graph=true api.compatibility.mode=false rudder.featureSwitch.directiveScriptEngine=disabled + rudder.policy.mode=${Enforce.name} + rudder.policy.mode.overridable=false """ val configWithFallback = configFile.withFallback(ConfigFactory.parseString(defaultConfig)) @@ -444,6 +479,18 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl save("rudder_compliance_heartbeatPeriod", value, Some(info)) } + def rudder_policy_mode_name(): Box[String] = get("rudder_policy_mode") + def set_rudder_policy_mode_name(name : PolicyMode, actor : EventActor, reason: Option[String]) : Box[Unit] = { + val info = ModifyGlobalPropertyInfo(ModifyComplianceModeEventType,actor,reason) + save("rudder_compliance_mode", name, Some(info)) + } + + def rudder_policy_overridable(): Box[Boolean] = get("rudder_policy_mode_overridable") + def set_rudder_policy_overridable(overridable : Boolean, actor: EventActor, reason: Option[String]) : Box[Unit] = { + val info = ModifyGlobalPropertyInfo(ModifyComplianceModeEventType,actor,reason) + save("rudder_compliance_mode", overridable, Some(info)) + } + /** * Send Metrics */ diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/components/popup/CreateCloneDirectivePopup.scala b/rudder-web/src/main/scala/com/normation/rudder/web/components/popup/CreateCloneDirectivePopup.scala index 59b10cb509d..44d092145e5 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/components/popup/CreateCloneDirectivePopup.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/components/popup/CreateCloneDirectivePopup.scala @@ -188,14 +188,16 @@ class CreateCloneDirectivePopup( if(formTracker.hasErrors) { onFailure & onFailureCallback() } else { - val cloneDirective = new Directive( - id = DirectiveId(uuidGen.newUuid), - techniqueVersion = directive.techniqueVersion, - parameters = directive.parameters, - name = directiveName.is, - shortDescription = directiveShortDescription.is, - _isEnabled = directive.isEnabled - ) + val cloneDirective = + new Directive( + id = DirectiveId(uuidGen.newUuid) + , techniqueVersion = directive.techniqueVersion + , parameters = directive.parameters + , name = directiveName.is + , shortDescription = directiveShortDescription.is + , _isEnabled = directive.isEnabled + , policyMode = directive.policyMode + ) roDirectiveRepository.getActiveTechniqueAndDirective(directive.id) match { case Full((activeTechnique, _)) => woDirectiveRepository.saveDirective(activeTechnique.id, cloneDirective, ModificationId(uuidGen.newUuid), CurrentUser.getActor, reasons.map(_.is)) match { diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/directive/DirectiveAPIService2.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/directive/DirectiveAPIService2.scala index 9b5c5c42f07..b95bab6e6e0 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/directive/DirectiveAPIService2.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/directive/DirectiveAPIService2.scala @@ -73,6 +73,7 @@ import com.normation.rudder.web.rest.RestDataSerializer import com.normation.rudder.domain.workflows.ChangeRequestId import com.normation.cfclerk.domain.TechniqueId import com.normation.cfclerk.services.TechniqueRepository +import com.normation.rudder.policyMode.Enforce case class DirectiveAPIService2 ( readDirective : RoDirectiveRepository @@ -224,7 +225,7 @@ case class DirectiveAPIService2 ( case Full(technique) => readDirective.getActiveTechnique(technique.id.name) match { case Full(Some(activeTechnique)) => - val baseDirective = Directive(directiveId,technique.id.version,Map(),name,"", _isEnabled = true) + val baseDirective = Directive(directiveId,technique.id.version,Map(),name,"", None, _isEnabled = true) actualDirectiveCreation(restDirective,baseDirective,activeTechnique,technique) case Full(None) => toJsonError(Some(directiveId.value), "Could not create Directive because the technique was not found") diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/configuration/DirectiveManagement.scala b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/configuration/DirectiveManagement.scala index 9ac2e0ea955..3c699d0b7be 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/configuration/DirectiveManagement.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/configuration/DirectiveManagement.scala @@ -67,6 +67,7 @@ import com.normation.rudder.authorization.NoRights import org.joda.time.DateTime import net.liftweb.http.js.JE.JsArray import com.normation.rudder.web.model.JsInitContextLinkUtil +import com.normation.rudder.policyMode.Enforce /** * Snippet for managing the System and Active Technique libraries. @@ -400,6 +401,7 @@ class DirectiveManagement extends DispatchSnippet with Loggable { , Map() , directiveDefaultName , "" + , None , "" , 5 , true