From 027987166c8d8d80977d51ae32ffef3244a33bb4 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] Fixes #8924: Policy mode API (Global, Directive, Node) --- .../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/nodes/NodeInfo.scala | 2 +- .../rudder/domain/policies/Directive.scala | 118 ++++++++-------- .../rudder/policyMode/PolicyMode.scala | 83 ++++++++++++ .../repository/ldap/LDAPEntityMapper.scala | 32 ++++- .../marshalling/XmlUnserialisationImpl.scala | 17 ++- .../services/nodes/NodeInfoService.scala | 17 +-- .../services/servers/NewNodeManager.scala | 20 +-- .../domain/policies/RuleTargetTest.scala | 3 +- .../services/policies/NodeConfigData.scala | 3 + .../policies/RuleValServiceTest.scala | 2 + .../scala/bootstrap/liftweb/AppConfig.scala | 20 +++ .../rudder/appconfig/ConfigService.scala | 49 ++++++- .../popup/CreateCloneDirectivePopup.scala | 18 +-- .../normation/rudder/web/rest/RestAPI.scala | 7 +- .../rudder/web/rest/RestDataSerializer.scala | 12 +- .../web/rest/RestExtractorService.scala | 39 +++++- .../rest/directive/DirectiveAPIService2.scala | 3 +- .../web/rest/directive/DirectiveApi.scala | 9 +- .../rudder/web/rest/node/NodeAPI5.scala | 4 +- .../rudder/web/rest/node/NodeAPI8.scala | 113 ++++++++++++++++ .../web/rest/node/NodeAPIService5.scala | 8 +- .../web/rest/node/NodeAPIService8.scala | 110 +++++++++++++++ .../rudder/web/rest/node/NodeApi.scala | 9 +- .../web/rest/node/NodeDetailLevel.scala | 7 +- .../web/rest/settings/SettingsApi.scala | 128 ++++++++++++++++++ .../configuration/DirectiveManagement.scala | 2 + .../rudder/web/snippet/node/Nodes.scala | 1 - 32 files changed, 708 insertions(+), 161 deletions(-) create mode 100644 rudder-core/src/main/scala/com/normation/rudder/policyMode/PolicyMode.scala create mode 100644 rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI8.scala create mode 100644 rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService8.scala create mode 100644 rudder-web/src/main/scala/com/normation/rudder/web/rest/settings/SettingsApi.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/nodes/NodeInfo.scala b/rudder-core/src/main/scala/com/normation/rudder/domain/nodes/NodeInfo.scala index 9d8e1a4824f..54fc4f3e135 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/domain/nodes/NodeInfo.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/domain/nodes/NodeInfo.scala @@ -50,7 +50,6 @@ import com.normation.inventory.domain.OsDetails import com.normation.inventory.domain.MachineUuid import com.normation.inventory.domain.KeyStatus - final case class MachineInfo( id : MachineUuid , machineType : MachineType @@ -92,5 +91,6 @@ final case class NodeInfo( val creationDate = node.creationDate val nodeReportingConfiguration = node.nodeReportingConfiguration val properties = node.properties + val policyMode = node.policyMode } 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..892ecc13c0f --- /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.toLowerCase() } 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..1a0b15d9151 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,10 @@ 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) match { + case None => Full(None) + case Some(value) => PolicyModeName.parse(value).map {Some(_) } + } } yield { Node( id @@ -172,6 +183,7 @@ class LDAPEntityMapper( , heartbeatConf ) , e.valuesFor(A_NODE_PROPERTY).map(unserializeLdapNodeProperty(_)).toSeq + , policyMode ) } } else { @@ -217,6 +229,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 +540,10 @@ 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) match { + case None => Full(None) + case Some(value) => PolicyModeName.parse(value).map {Some(_) } + } version <- tryo(TechniqueVersion(s_version)) name = e(A_NAME).getOrElse(id) params = parsePolicyVariables(e.valuesFor(A_DIRECTIVE_VARIABLES).toSeq) @@ -537,8 +554,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 +583,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/nodes/NodeInfoService.scala b/rudder-core/src/main/scala/com/normation/rudder/services/nodes/NodeInfoService.scala index 32af4bd60fc..2e47f85677d 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/nodes/NodeInfoService.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/nodes/NodeInfoService.scala @@ -63,8 +63,6 @@ import com.normation.inventory.ldap.core.InventoryMapper import com.normation.inventory.ldap.core.LDAPConstants import com.normation.rudder.domain.nodes.MachineInfo - - /* * General logic for the cache implementation of NodeInfo. * The general idea is to limit at maximum: @@ -93,7 +91,6 @@ import com.normation.rudder.domain.nodes.MachineInfo * being rebuilt (so, much data on the wires, jvm gb pression, etc). */ - /** * A case class used to represent the minimal * information needed to get a NodeInfo @@ -118,7 +115,6 @@ trait NodeInfoService { */ def getNodeInfo(nodeId: NodeId) : Box[Option[NodeInfo]] - /** * Get the node (not inventory). * Most of the info are also in node info, @@ -127,7 +123,6 @@ trait NodeInfoService { */ def getNode(nodeId: NodeId): Box[Node] - /** * Get all node infos. * That method try to return the maximum @@ -137,7 +132,6 @@ trait NodeInfoService { */ def getAll() : Box[Map[NodeId, NodeInfo]] - /** * Get all nodes. * That method try to return the maximum @@ -154,7 +148,6 @@ trait NodeInfoService { */ def getAllSystemNodeIds() : Box[Seq[NodeId]] - /** * Getting something like a nodeinfo for pending / deleted nodes */ @@ -181,7 +174,7 @@ object NodeInfoService { //, isPolicyServer <- this one is special and decided based on objectClasss rudderPolicyServer //, creationDate, nodeReportingConfiguration, properties , A_NODE_UUID, A_NAME, A_DESCRIPTION, A_IS_BROKEN, A_IS_SYSTEM - , A_SERIALIZED_AGENT_RUN_INTERVAL, A_SERIALIZED_HEARTBEAT_RUN_CONFIGURATION, A_NODE_PROPERTY + , A_SERIALIZED_AGENT_RUN_INTERVAL, A_SERIALIZED_HEARTBEAT_RUN_CONFIGURATION, A_NODE_PROPERTY, A_POLICY_MODE // machine inventory // MachineUuid @@ -201,12 +194,10 @@ object NodeInfoService { , A_CONTAINER_DN, A_OS_RAM, A_KEY_STATUS )).toSeq - val A_MOD_TIMESTAMP = "modifyTimestamp" } - /* * For test, we need a way to split the cache part from its retrieval. */ @@ -324,7 +315,6 @@ trait NodeInfoServiceCached extends NodeInfoService with Loggable with CachedRe } } - //actual logic that check what to do (invalidate cache or not) val t0 = System.currentTimeMillis @@ -444,7 +434,6 @@ trait NodeInfoServiceCached extends NodeInfoService with Loggable with CachedRe override final def getPendingNodeInfo(nodeId: NodeId): Box[Option[NodeInfo]] = getNotAcceptedNodeInfo(nodeId, PendingInventory) override final def getDeletedNodeInfo(nodeId: NodeId): Box[Option[NodeInfo]] = getNotAcceptedNodeInfo(nodeId, RemovedInventory) - /** * Clear cache. Try a reload asynchronously, disregarding * the result @@ -516,11 +505,8 @@ class NaiveNodeInfoServiceCachedImpl( }) } - } - - /** * A cache on top of node info service. * @@ -537,7 +523,6 @@ class NodeInfoServiceCachedImpl( ) extends NodeInfoServiceCached { import NodeInfoService._ - /* * Check if node related infos are up to date. * 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/bootstrap/liftweb/AppConfig.scala b/rudder-web/src/main/scala/bootstrap/liftweb/AppConfig.scala index a55d7f18afc..dc2295f03c6 100644 --- a/rudder-web/src/main/scala/bootstrap/liftweb/AppConfig.scala +++ b/rudder-web/src/main/scala/bootstrap/liftweb/AppConfig.scala @@ -724,6 +724,20 @@ object RudderConfig extends Loggable { ) } + val nodeApi8 = { + new NodeAPI8 ( + nodeApi6 + , new NodeApiService8( + woNodeRepository + , nodeInfoService + , uuidGen + , asyncDeploymentAgent + ) + , restExtractorService + , restDataSerializer + ) + } + val parameterApiService2 = new ParameterApiService2 ( roLDAPParameterRepository @@ -774,6 +788,8 @@ object RudderConfig extends Loggable { val complianceApi6 = new ComplianceAPI7(restExtractorService, complianceAPIService, v6compatibility = true) val complianceApi7 = new ComplianceAPI7(restExtractorService, complianceAPIService) + val settingsApi8 = new SettingsAPI8(restExtractorService, configService) + // First working version with support for rules, directives, nodes and global parameters val apiV2 : List[RestAPI] = ruleApi2 :: directiveApi2 :: groupApi2 :: nodeApi2 :: parameterApi2 :: Nil // Add change request support @@ -786,6 +802,8 @@ object RudderConfig extends Loggable { val apiV6 : List[RestAPI] = techniqueApi6 ::complianceApi6 :: nodeApi6 :: ruleApi6 :: groupApi6 :: apiV5.filter( _ != nodeApi5).filter( _ != ruleApi2).filter( _ != groupApi5) // apiv7 just add compatible changes on compliances, adding "level" option and "compliance mode" attribute in response val apiV7 = complianceApi7 :: apiV6.filter( _ != complianceApi6) + // apiv8 add policy mode in node API and settings API + val apiV8 = nodeApi8 :: settingsApi8 :: apiV7.filter( _ != nodeApi6) val apis = { Map ( @@ -801,6 +819,8 @@ object RudderConfig extends Loggable { , ( ApiVersion(6,false) -> apiV6 ) //Rudder 3.2 , ( ApiVersion(7,false) -> apiV7 ) + //Rudder 4.0 + , ( ApiVersion(8,false) -> apiV8 ) ) } 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..fda130d2974 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,20 @@ trait ReadConfigService { def rudder_compliance_heartbeatPeriod(): Box[Int] + /** + * Policy mode: See PolicyMode class for more details + */ + def rudder_global_policy_mode(): Box[GlobalPolicyMode] = { + for { + mode <- rudder_policy_mode_name + overridable <- rudder_policy_overridable + } yield { + GlobalPolicyMode(mode,overridable) + } + } + def rudder_policy_mode_name(): Box[PolicyMode] + def rudder_policy_overridable(): Box[Boolean] + /** * Send Metrics */ @@ -246,6 +260,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 +310,8 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl display.changes.graph=true api.compatibility.mode=false rudder.featureSwitch.directiveScriptEngine=disabled + rudder.policy.mode.name=${Enforce.name} + rudder.policy.mode.overridable=false """ val configWithFallback = configFile.withFallback(ConfigFactory.parseString(defaultConfig)) @@ -444,6 +478,18 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl save("rudder_compliance_heartbeatPeriod", value, Some(info)) } + def rudder_policy_mode_name(): Box[PolicyMode] = get("rudder_policy_mode_name").flatMap { PolicyModeName.parse(_) } + def set_rudder_policy_mode_name(name : PolicyMode, actor : EventActor, reason: Option[String]) : Box[Unit] = { + val info = ModifyGlobalPropertyInfo(ModifyComplianceModeEventType,actor,reason) + save("rudder_policy_mode_name", 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_policy_mode_overridable", overridable, Some(info)) + } + /** * Send Metrics */ @@ -481,7 +527,6 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl ///// Feature switches ///// ///// - /** * Should we evaluate scripts in the variables? */ 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/RestAPI.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestAPI.scala index 935d147a562..0fad1289a2e 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestAPI.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestAPI.scala @@ -47,8 +47,6 @@ import net.liftweb.json.JString import net.liftweb.json.JValue import scala.language.implicitConversions - - /** * The trait of all API definition * It needs to define its kind (will be the url prefix ) @@ -63,7 +61,6 @@ trait RestAPI extends RestHelper{ } - /** * The class that actually dispatch the API * It dispatchs them from a map of API definition @@ -82,6 +79,7 @@ case class APIDispatcher ( apis.foreach{ api => serve("api" / s"${version}" / s"${api.kind}" prefix api.requestDispatch(v) ) + serve("secure" / "api" / s"${version}" / s"${api.kind}" prefix api.requestDispatch(v) ) } } @@ -91,6 +89,7 @@ case class APIDispatcher ( api => // ... and Dispatch it serve("api" / "latest" / s"${api.kind}" prefix api.requestDispatch(latest)) + serve("secure" / "api" / "latest" / s"${api.kind}" prefix api.requestDispatch(latest)) } // regroup api by kind, to be able to dispatch header api version @@ -125,7 +124,6 @@ case class APIDispatcher ( serve("api" / s"${kind}" prefix requestDispatch) } - serve { case Get("api" :: "info" :: Nil,req) => implicit val action = "ApiGeneralInformations" @@ -144,7 +142,6 @@ case class APIDispatcher ( ( "all" -> availableVersions) ) - RestUtils.toJsonResponse(None, versions) } diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestDataSerializer.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestDataSerializer.scala index b9c13e86baf..41c2a0bd750 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestDataSerializer.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestDataSerializer.scala @@ -79,6 +79,7 @@ trait RestDataSerializer { def serializeServerInfo (srv : Srv, status : String) : JValue def serializeNodeInfo(nodeInfo : NodeInfo, status : String, tagFixed : Boolean) : JValue + def serializeNode(node : Node) : JValue def serializeInventory(inventory: FullInventory, status: String, tagFixed: Boolean) : JValue @@ -115,6 +116,14 @@ case class RestDataSerializerImpl ( ) } + def serializeNode(node : Node) : JValue = { + import com.normation.rudder.domain.nodes.JsonSerialisation._ + ( ("id" -> node.id.value) + ~ ("properties" -> node.properties.toApiJson) + ~ ("policyMode" -> node.policyMode.map(_.name).getOrElse("default")) + ) + } + def serializeInventory(nodeInfo: NodeInfo, status:InventoryStatus, inventory : Option[FullInventory], software: Seq[Software], detailLevel : NodeDetailLevel, apiVersion: ApiVersion) : JValue = { val filteredLevel = if(apiVersion.value <= 4) { CustomDetailLevel(MinimalDetailLevel, detailLevel.fields - "properties") @@ -288,6 +297,7 @@ case class RestDataSerializerImpl ( ~ ("priority" -> directive.priority) ~ ("enabled" -> directive.isEnabled ) ~ ("system" -> directive.isSystem ) + ~ ("policyMode" -> directive.policyMode.map(_.name).getOrElse("default")) ) extendResponseCompatibility(base,extension) } @@ -500,7 +510,7 @@ case class RestDataSerializerImpl ( ) Full(extendResponseCompatibility(base, extension)) } catch { - case e:Exception => e + case e:Exception => val errorMsg = "Error while trying to serialize Directive Diff. cause is: " + e.getMessage() logger.error(errorMsg) Failure(errorMsg) diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestExtractorService.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestExtractorService.scala index 81f7d60091b..6a085d863b6 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestExtractorService.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/RestExtractorService.scala @@ -73,6 +73,8 @@ import com.normation.rudder.services.queries.StringCriterionLine import com.normation.rudder.domain.queries.QueryReturnType import com.normation.rudder.domain.queries.NodeReturnType import com.normation.rudder.services.queries.StringQuery +import com.normation.rudder.policyMode.PolicyMode +import com.normation.rudder.policyMode.PolicyModeName case class RestExtractorService ( readRule : RoRuleRepository @@ -229,6 +231,13 @@ case class RestExtractorService ( parseSectionVal(parse(value)).map(SectionVal.toMapVariables(_)) } + private[this] def convertToPolicyMode (value:String) : Box[Option[PolicyMode]] = { + value.toLowerCase() match { + case "default" => Full(None) + case _ => PolicyModeName.parse(value).map(Some(_)) + } + } + private[this] def extractJsonDirectiveParam (json: JValue ): Box[Option[Map[String,Seq[String]]]] = { json \\ "parameters" match { case JObject(Nil) => Full(None) @@ -589,7 +598,6 @@ case class RestExtractorService ( } } - def extractParameter (params : Map[String,List[String]]) : Box[RestParameter] = { for { description <- extractOneValue(params, "description")() @@ -615,6 +623,15 @@ case class RestExtractorService ( } } + def extractNode (params : Map[String, List[String]]) : Box[RestNode] = { + for { + properties <- extractNodeProperties(params) + mode <- extractOneValue(params, "policyMode")(convertToPolicyMode) + } yield { + RestNode(properties,mode) + } + } + /* * expecting json: * { "properties": [ @@ -623,11 +640,20 @@ case class RestExtractorService ( * , {"name":"plop", "value":"plop" } * ] } */ - def extractNodePropertiesrFromJSON (json : JValue) : Box[RestNode] = { + def extractNodePropertiesrFromJSON (json : JValue) : Box[RestNodeProperties] = { import net.liftweb.json.JsonParser._ implicit val formats = DefaultFormats - Box(json.extractOpt[RestNode]) ?~! "Error when extracting node information" + Box(json.extractOpt[RestNodeProperties]) ?~! "Error when extracting node properties" + } + + def extractNodeFromJSON (json : JValue) : Box[RestNode] = { + for { + properties <- extractNodePropertiesrFromJSON(json) + mode <- extractOneValueJson(json, "policyMode")(convertToPolicyMode) + } yield { + RestNode(properties.properties,mode) + } } /* @@ -654,8 +680,9 @@ case class RestExtractorService ( parameters <- extractOneValue(params, "parameters")(convertToDirectiveParam) techniqueName <- extractOneValue(params, "techniqueName")(x => Full(TechniqueName(x))) techniqueVersion <- extractOneValue(params, "techniqueVersion")(x => Full(TechniqueVersion(x))) + policyMode <- extractOneValue(params, "policyMode")(convertToPolicyMode) } yield { - RestDirective(name,shortDescription,longDescription,enabled,parameters,priority, techniqueName, techniqueVersion) + RestDirective(name,shortDescription,longDescription,enabled,parameters,priority, techniqueName, techniqueVersion, policyMode) } } @@ -693,8 +720,9 @@ case class RestExtractorService ( parameters <- extractJsonDirectiveParam(json) techniqueName <- extractOneValueJson(json, "techniqueName")(x => Full(TechniqueName(x))) techniqueVersion <- extractOneValueJson(json, "techniqueVersion")(x => Full(TechniqueVersion(x))) + policyMode <- extractOneValueJson(json, "policyMode")(convertToPolicyMode) } yield { - RestDirective(name,shortDescription,longDescription,enabled,parameters,priority,techniqueName,techniqueVersion) + RestDirective(name,shortDescription,longDescription,enabled,parameters,priority,techniqueName,techniqueVersion,policyMode) } } @@ -801,5 +829,4 @@ case class RestExtractorService ( } } - } 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/rest/directive/DirectiveApi.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/directive/DirectiveApi.scala index 7f737f5ba3a..9adfb8ba023 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/directive/DirectiveApi.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/directive/DirectiveApi.scala @@ -48,6 +48,7 @@ import com.normation.rudder.web.rest.RestAPI import com.normation.cfclerk.domain.TechniqueName import com.normation.rudder.domain.policies.ActiveTechnique import com.normation.cfclerk.domain.Technique +import com.normation.rudder.policyMode.PolicyMode trait DirectiveAPI extends RestAPI { val kind = "directives" @@ -62,6 +63,7 @@ case class RestDirective( , priority : Option[Int] , techniqueName : Option[TechniqueName] , techniqueVersion : Option[TechniqueVersion] + , policyMode : Option[Option[PolicyMode]] ) { val onlyName = name.isDefined && @@ -71,7 +73,8 @@ case class RestDirective( parameters.isEmpty && priority.isEmpty && techniqueName.isEmpty && - techniqueVersion.isEmpty + techniqueVersion.isEmpty && + policyMode.isEmpty def updateDirective(directive:Directive) = { val updateName = name.getOrElse(directive.name) @@ -81,14 +84,16 @@ case class RestDirective( val updateTechniqueVersion = techniqueVersion.getOrElse(directive.techniqueVersion) val updateParameters = parameters.getOrElse(directive.parameters) val updatePriority = priority.getOrElse(directive.priority) + val updateMode = policyMode.getOrElse(directive.policyMode) directive.copy( name = updateName , shortDescription = updateShort , longDescription = updateLong - , _isEnabled = updateEnabled + , _isEnabled = updateEnabled , parameters = updateParameters , techniqueVersion = updateTechniqueVersion , priority = updatePriority + , policyMode = updateMode ) } diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI5.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI5.scala index 440c1296551..a3becde2434 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI5.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI5.scala @@ -50,14 +50,12 @@ import net.liftweb.json.JsonDSL._ import com.normation.rudder.web.rest.RestUtils import com.normation.rudder.web.rest.ApiVersion - class NodeAPI5 ( apiV4 : NodeAPI4 , apiV5service : NodeApiService5 , restExtractor: RestExtractorService ) extends RestHelper with NodeAPI with Loggable{ - val v5Dispatch : PartialFunction[Req, () => Box[LiftResponse]] = { case id :: Nil JsonPost body -> req => { @@ -73,7 +71,7 @@ class NodeAPI5 ( } case Post(id :: Nil, req) => { - val restNode = restExtractor.extractNodeProperties(req.params).map(RestNode(_)) + val restNode = restExtractor.extractNodeProperties(req.params).map(RestNodeProperties(_)) apiV5service.updateRestNode(NodeId(id), restNode, req) } } diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI8.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI8.scala new file mode 100644 index 00000000000..dbd649d3a4b --- /dev/null +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPI8.scala @@ -0,0 +1,113 @@ +/* +************************************************************************************* +* Copyright 2013 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.web.rest.node + +import com.normation.inventory.domain.NodeId +import net.liftweb.common.Box +import net.liftweb.common.Loggable +import net.liftweb.http.LiftResponse +import net.liftweb.http.Req +import net.liftweb.http.rest.RestHelper +import com.normation.rudder.web.rest.RestExtractorService +import com.normation.rudder.web.rest.RestUtils._ +import net.liftweb.common._ +import net.liftweb.json.JsonDSL._ +import com.normation.rudder.web.rest.RestUtils +import com.normation.rudder.web.rest.ApiVersion +import com.normation.rudder.web.rest.RestDataSerializer +import com.normation.rudder.domain.nodes.Node + +class NodeAPI8 ( + apiV6 : NodeAPI6 + , apiV8service : NodeApiService8 + , extractor : RestExtractorService + , serializer : RestDataSerializer +) extends RestHelper with NodeAPI with Loggable{ + + private[this] def serialize(node : Node) = { + serializer.serializeNode(node) + } + + val v8Dispatch : PartialFunction[Req, () => Box[LiftResponse]] = { + + case id :: Nil JsonPost body -> req => { + implicit val prettify = extractor.extractPrettify(req.params) + implicit val action = "updateNode" + val actor = RestUtils.getActor(req) + + (for { + json <- req.json ?~! "No Json data sent" + restNode <- extractor.extractNodeFromJSON(json) + reason <- extractor.extractReason(req.params) + result <- apiV8service.updateRestNode(NodeId(id), restNode, actor, reason) + } yield { + toJsonResponse(Some(id), serialize(result)) + }) match { + case Full(response) => + response + case eb : EmptyBox => + val fail = eb ?~! s"An error occured while updating Node '${id}'" + toJsonError(Some(id), fail.messageChain) + } + } + + case Post(id :: Nil, req) => { + implicit val prettify = extractor.extractPrettify(req.params) + implicit val action = "updateNode" + val actor = RestUtils.getActor(req) + + (for { + restNode <- extractor.extractNode(req.params) + reason <- extractor.extractReason(req.params) + result <- apiV8service.updateRestNode(NodeId(id), restNode, actor, reason) + } yield { + toJsonResponse(Some(id), serialize(result)) + }) match { + case Full(response) => + response + case eb : EmptyBox => + val fail = eb ?~! s"An error occured while updating Node '${id}'" + toJsonError(Some(id), fail.messageChain) + } + } + } + + override def requestDispatch(apiVersion: ApiVersion) : PartialFunction[Req, () => Box[LiftResponse]] = { + v8Dispatch orElse apiV6.requestDispatch(apiVersion) + } +} diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService5.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService5.scala index e1747c05e9b..25f99b777c4 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService5.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService5.scala @@ -56,8 +56,6 @@ import net.liftweb.http.Req import net.liftweb.json._ import net.liftweb.json.JsonDSL._ - - class NodeApiService5 ( nodeRepository : WoNodeRepository , nodeInfoService: NodeInfoService @@ -66,8 +64,7 @@ class NodeApiService5 ( , asyncRegenerate: AsyncDeploymentAgent ) extends Loggable { - - def updateRestNode(nodeId: NodeId, boxRestNode: Box[RestNode], req: Req) = { + def updateRestNode(nodeId: NodeId, boxRestNode: Box[RestNodeProperties], req: Req) = { implicit val prettify = restExtractor.extractPrettify(req.params) implicit val action = "updateNodeProperties" val modId = ModificationId(uuidGen.newUuid) @@ -94,7 +91,6 @@ class NodeApiService5 ( } } - /** * Update a set of properties with the map: * - if a key of the map matches a property name, @@ -121,5 +117,3 @@ class NodeApiService5 ( } } } - - diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService8.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService8.scala new file mode 100644 index 00000000000..75977dc2dbf --- /dev/null +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeAPIService8.scala @@ -0,0 +1,110 @@ +/* +************************************************************************************* +* Copyright 2013 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.web.rest.node + +import com.normation.eventlog.ModificationId + +import com.normation.inventory.domain._ +import com.normation.rudder.batch.AsyncDeploymentAgent +import com.normation.rudder.batch.AutomaticStartDeployment +import com.normation.rudder.domain.nodes.JsonSerialisation._ +import com.normation.rudder.domain.nodes.NodeProperty +import com.normation.rudder.repository.WoNodeRepository +import com.normation.rudder.services.nodes.NodeInfoService +import com.normation.rudder.web.model.CurrentUser +import com.normation.rudder.web.rest.RestExtractorService +import com.normation.rudder.web.rest.RestUtils._ +import com.normation.rudder.web.rest.RestUtils +import com.normation.utils.StringUuidGenerator + +import net.liftweb.common._ +import net.liftweb.http.Req +import net.liftweb.json._ +import net.liftweb.json.JsonDSL._ +import com.normation.eventlog.EventActor +import com.normation.rudder.domain.nodes.Node + +class NodeApiService8 ( + nodeRepository : WoNodeRepository + , nodeInfoService: NodeInfoService + , uuidGen : StringUuidGenerator + , asyncRegenerate: AsyncDeploymentAgent +) extends Loggable { + + def updateRestNode(nodeId: NodeId, restNode: RestNode, actor : EventActor, reason : Option[String]) : Box[Node] = { + + val modId = ModificationId(uuidGen.newUuid) + + for { + node <- nodeInfoService.getNode(nodeId) + updated = node.copy(properties = updateProperties(node.properties, restNode.properties)) + saved <- if(updated == node) Full(node) + else nodeRepository.updateNodeProperties(updated.id, updated.properties, modId, actor, reason) + } yield { + if(node != updated) { + asyncRegenerate ! AutomaticStartDeployment(ModificationId(uuidGen.newUuid), CurrentUser.getActor) + } + saved + } + } + + /** + * Update a set of properties with the map: + * - if a key of the map matches a property name, + * use the map value for the key as value for + * the property + * - if the value is the emtpy string, remove + * the property + */ + def updateProperties(props: Seq[NodeProperty], updates: Option[Seq[NodeProperty]]) = { + updates match { + case None => props + case Some(u) => + val values = u.map { case NodeProperty(k, v) => (k, v)}.toMap + val existings = props.map(_.name).toSet + //for news values, don't keep empty + val news = (values -- existings).collect { case(k,v) if(v.nonEmpty) => NodeProperty(k,v) } + props.flatMap { case p@NodeProperty(name, value) => + values.get(name) match { + case None => Some(p) + case Some("") => None + case Some(x) => Some(NodeProperty(name, x)) + } + } ++ news + } + } +} diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeApi.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeApi.scala index 2fc641d051e..54f9c4c2d95 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeApi.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeApi.scala @@ -44,12 +44,17 @@ import net.liftweb.http.Req import net.liftweb.http.rest.RestHelper import com.normation.rudder.web.rest.RestAPI import com.normation.rudder.domain.nodes.NodeProperty +import com.normation.rudder.policyMode.PolicyMode trait NodeAPI extends RestAPI { val kind = "nodes" } -case class RestNode( - properties: Option[Seq[NodeProperty]] +case class RestNodeProperties( + properties : Option[Seq[NodeProperty]] ) +case class RestNode ( + properties : Option[Seq[NodeProperty]] + , policyMode : Option[Option[PolicyMode]] +) diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeDetailLevel.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeDetailLevel.scala index 91252ba8c97..f109dd99825 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeDetailLevel.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/node/NodeDetailLevel.scala @@ -109,7 +109,6 @@ case class CustomDetailLevel ( object NodeDetailLevel { - val otherDefaultFields = List( "os" , "architectureDescription" @@ -121,6 +120,7 @@ object NodeDetailLevel { , "policyServerId" , "managementTechnology" , "properties" + , "policyMode" ) val otherAllFields = List( @@ -170,6 +170,7 @@ object NodeDetailLevel { val arch : NodeInfo => JValue = (inv: NodeInfo) => inv.archDescription val inventoryDate: NodeInfo => JValue = (inv: NodeInfo) => DateFormaterService.getFormatedDate(inv.inventoryDate) val properties : NodeInfo => JValue = (inv: NodeInfo) => inv.properties.toApiJson + val policyMode : NodeInfo => JValue = (inv: NodeInfo) => inv.policyMode.map(_.name).getOrElse[String]("default") val os = { ( inv : NodeInfo ) => @@ -203,7 +204,6 @@ object NodeDetailLevel { ( "serialNumber" -> inv.machine.flatMap(_.systemSerial)) } - val ips = { ( inv : NodeInfo ) => val ips =inv.ips.map(ip => JString(ip)).toList @@ -220,8 +220,6 @@ object NodeDetailLevel { JArray(agents) } - - Map ( ( "id" -> id ) , ( "hostname" -> hostname ) @@ -593,5 +591,4 @@ object NodeDetailLevel { } - } diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/rest/settings/SettingsApi.scala b/rudder-web/src/main/scala/com/normation/rudder/web/rest/settings/SettingsApi.scala new file mode 100644 index 00000000000..6e48ccd9b3a --- /dev/null +++ b/rudder-web/src/main/scala/com/normation/rudder/web/rest/settings/SettingsApi.scala @@ -0,0 +1,128 @@ +/* +************************************************************************************* +* 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.web.rest.node + +import net.liftweb.common.Box +import net.liftweb.common.Loggable +import net.liftweb.http.LiftResponse +import net.liftweb.http.Req +import net.liftweb.http.rest.RestHelper +import com.normation.rudder.web.rest.RestAPI +import net.liftweb.json.JsonAST.JValue +import com.normation.rudder.web.rest.RestExtractorService +import com.normation.rudder.web.rest.RestUtils +import com.normation.rudder.web.rest.ApiVersion +import com.normation.rudder.appconfig._ +import net.liftweb.common.Empty +import com.normation.eventlog.EventActor +import net.liftweb.common.Full +import net.liftweb.common.Failure +import net.liftweb.json.JsonAST.JString +import com.normation.rudder.policyMode.PolicyModeName +import com.normation.utils.StringUuidGenerator +import net.liftweb.json.JsonAST.JBool + +trait SettingsApi extends RestAPI { + val kind = "settings" +} + +class SettingsAPI8( + restExtractor : RestExtractorService + , configService : ReadConfigService with UpdateConfigService +) extends SettingsApi { + + def response ( function : Box[JValue], req : Req, errorMessage : String)(implicit action : String) : LiftResponse = { + RestUtils.response(restExtractor, kind)(function, req, errorMessage) + } + override def requestDispatch(apiVersion : ApiVersion): PartialFunction[Req, () => Box[LiftResponse]] = { + case Get("global_policy_mode" :: Nil, req) => { + import net.liftweb.json.JsonDSL._ + val mode : Box[JValue] = configService.rudder_policy_mode_name().map(("global_policy_mode" -> _.name)) + RestUtils.response(restExtractor, "settings")(mode, req, "Could not get global policy mode")("getSetting") + } + case Post("global_policy_mode" :: Nil, req) => { + import net.liftweb.json.JsonDSL._ + val newValue : Box[JValue] = for { + requestValue <- req.json match { + case Full(json) => json \ "value" match { + case JString(value) => Full(value) + case x => Failure("Invalid value "+x) + } + case _ => req.params.get("value") match { + case Some(value :: Nil) => Full(value) + case _ => Failure("No value defined in request") + } + } + newMode <- PolicyModeName.parse(requestValue) + actor = RestUtils.getActor(req) + saved <- configService.set_rudder_policy_mode_name(newMode, actor, None) + } yield { + import net.liftweb.json.JsonDSL._ + ("global_policy_mode" -> newMode.name) + } + RestUtils.response(restExtractor, "settings")(newValue, req, "Could not get global policy mode")("setSetting") + } + + case Get("global_policy_mode_overridable" :: Nil, req) => { + import net.liftweb.json.JsonDSL._ + val mode : Box[JValue] = configService.rudder_policy_overridable().map(("global_policy_mode_overridable" -> _)) + RestUtils.response(restExtractor, "settings")(mode, req, "Could not get global policy mode")("getSetting") + } + case Post("global_policy_mode_overridable" :: Nil, req) => { + import net.liftweb.json.JsonDSL._ + val newValue : Box[JValue] = for { + requestValue <- req.json match { + case Full(json) => json \ "value" match { + case JBool(value) => Full(value) + case x => Failure("Invalid value "+x) + } + case _ => req.params.get("value") match { + case Some(value :: Nil) => Full(value.toBoolean) + case _ => Failure("No value defined in request") + } + } + actor = RestUtils.getActor(req) + saved <- configService.set_rudder_policy_overridable(requestValue, actor, None) + } yield { + import net.liftweb.json.JsonDSL._ + ("global_policy_mode_overridable" -> requestValue) + } + RestUtils.response(restExtractor, "settings")(newValue, req, "Could not get global policy mode")("setSetting") + } + } +} 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 diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/node/Nodes.scala b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/node/Nodes.scala index 7c7201f80b3..74e750f0d36 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/node/Nodes.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/node/Nodes.scala @@ -43,7 +43,6 @@ import bootstrap.liftweb.RudderConfig import scala.xml.NodeSeq import net.liftweb.http.js.JsCmds._ - class Nodes extends StatefulSnippet with Loggable { private[this] val nodeInfoService = RudderConfig.nodeInfoService val srvGrid = RudderConfig.srvGrid