diff --git a/rudder-core/src/main/scala/com/normation/rudder/repository/NodeRepository.scala b/rudder-core/src/main/scala/com/normation/rudder/repository/NodeRepository.scala index c277ea6ff3..e9ea46a9ff 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/repository/NodeRepository.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/repository/NodeRepository.scala @@ -44,6 +44,7 @@ import com.normation.rudder.reports.AgentRunInterval import com.normation.rudder.reports.HeartbeatConfiguration import net.liftweb.common._ import com.normation.inventory.domain.NodeId +import com.normation.rudder.domain.policies.PolicyMode /** * Node Repository diff --git a/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPNodeRepository.scala b/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPNodeRepository.scala index 83d6d6949f..ef7a69ef7c 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPNodeRepository.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/repository/ldap/LDAPNodeRepository.scala @@ -50,6 +50,7 @@ import com.normation.rudder.reports.AgentRunInterval import com.normation.rudder.reports.HeartbeatConfiguration import net.liftweb.common._ import com.normation.rudder.repository.EventLogRepository +import com.normation.rudder.domain.policies.PolicyMode class WoLDAPNodeRepository( nodeDit : NodeDit diff --git a/rudder-web/src/main/scala/bootstrap/liftweb/AppConfig.scala b/rudder-web/src/main/scala/bootstrap/liftweb/AppConfig.scala index ba0d1d4ed4..690b3d21be 100644 --- a/rudder-web/src/main/scala/bootstrap/liftweb/AppConfig.scala +++ b/rudder-web/src/main/scala/bootstrap/liftweb/AppConfig.scala @@ -387,7 +387,7 @@ object RudderConfig extends Loggable { val reportsRepository : ReportsRepository = reportsRepositoryImpl val eventLogDeploymentService: EventLogDeploymentService = eventLogDeploymentServiceImpl val allBootstrapChecks : BootstrapChecks = allChecks - lazy val srvGrid = new SrvGrid(roAgentRunsRepository, asyncComplianceService) + lazy val srvGrid = new SrvGrid(roAgentRunsRepository, asyncComplianceService, configService) val findExpectedReportRepository : FindExpectedReportRepository = findExpectedRepo val historizationRepository : HistorizationRepository = historizationJdbcRepository val roApiAccountRepository : RoApiAccountRepository = roLDAPApiAccountRepository @@ -1117,7 +1117,7 @@ object RudderConfig extends Loggable { , diffRepos , PendingInventory ) - private[this] lazy val nodeGridImpl = new NodeGrid(ldapFullInventoryRepository, nodeInfoServiceImpl) + private[this] lazy val nodeGridImpl = new NodeGrid(ldapFullInventoryRepository, nodeInfoServiceImpl, configService) private[this] lazy val modificationService = new ModificationService(logRepository,gitModificationRepository,itemArchiveManagerImpl,uuidGen) private[this] lazy val eventListDisplayerImpl = new EventListDisplayer( @@ -1748,7 +1748,9 @@ object RudderConfig extends Loggable { roLdapRuleRepository , roLdapDirectiveRepository , reportingServiceImpl - , techniqueRepositoryImpl) + , techniqueRepositoryImpl + , configService + ) private[this] lazy val propertyRepository = new RudderPropertiesSquerylRepository( squerylDatasourceProvider , reportsRepository ) diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/components/AgentPolicyModeEditForm.scala b/rudder-web/src/main/scala/com/normation/rudder/web/components/AgentPolicyModeEditForm.scala new file mode 100644 index 0000000000..2cdebe7991 --- /dev/null +++ b/rudder-web/src/main/scala/com/normation/rudder/web/components/AgentPolicyModeEditForm.scala @@ -0,0 +1,33 @@ +package com.normation.rudder.web.components + +import net.liftweb.http.DispatchSnippet +import net.liftweb.common._ +import net.liftweb.http.{SHtml,S} +import scala.xml._ +import net.liftweb.http.js._ +import JsCmds._ +import JE._ +import net.liftweb.util.Helpers +import net.liftweb.util.Helpers._ +import net.liftweb.http.Templates + +class AgentPolicyModeEditForm extends DispatchSnippet with Loggable { + + // Html template + def templatePath = List("templates-hidden", "components", "ComponentAgentPolicyMode") + def template() = Templates(templatePath) match { + case Empty | Failure(_,_,_) => + sys.error("Template for Agent Policy Mode configuration not found. I was looking for %s.html" + .format(templatePath.mkString("/"))) + case Full(n) => n + } + def agentPolicyModeTemplate = chooseTemplate("agentpolicymode", "form", template) + + def dispatch = { + case "cfagentPolicyModeConfiguration" => (xml) => cfagentPolicyModeConfiguration + } + + def cfagentPolicyModeConfiguration = { + agentPolicyModeTemplate ++ Script(OnLoad(JsRaw("angular.bootstrap('#auditMode', ['auditmode']);"))) + } +} diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/components/ComplianceModeEditForm.scala b/rudder-web/src/main/scala/com/normation/rudder/web/components/ComplianceModeEditForm.scala index 1c92a7ebf8..98a2f32d29 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/components/ComplianceModeEditForm.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/components/ComplianceModeEditForm.scala @@ -212,9 +212,9 @@ class ComplianceModeEditForm [T <: ComplianceMode] ( s""" angular.bootstrap("#complianceMode", ['complianceMode']); var scope = angular.element($$("#complianceModeController")).scope(); - scope.$$apply(function(){ - scope.init(${toJs(complianceMode)}, ${toJs(globalMode)}, ${isNodePage} ,${callback.toJsCmd}, "${S.contextPath}", ${allModes}); - } ); + scope.$$apply(function(){ + scope.init(${toJs(complianceMode)}, ${toJs(globalMode)}, ${isNodePage} ,${callback.toJsCmd}, "${S.contextPath}", ${allModes}); + }); """ }) match { case eb:EmptyBox => diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/components/DirectiveEditForm.scala b/rudder-web/src/main/scala/com/normation/rudder/web/components/DirectiveEditForm.scala index 81b564e398..9cf538ceaf 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/components/DirectiveEditForm.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/components/DirectiveEditForm.scala @@ -68,6 +68,10 @@ import com.normation.cfclerk.domain.TechniqueName import com.normation.rudder.web.components.popup.ModificationValidationPopup import com.normation.cfclerk.domain.TechniqueId import com.normation.cfclerk.domain.TechniqueVersion +import com.normation.rudder.web.rest.node.SettingsAPI8 +import com.normation.rudder.web.rest.node.SettingsApi +import com.normation.rudder.domain.policies.PolicyMode.Verify +import com.normation.rudder.domain.policies.PolicyMode.Enforce object DirectiveEditForm { @@ -100,17 +104,18 @@ object DirectiveEditForm { * Parameters can not be null. */ class DirectiveEditForm( - htmlId_policyConf : String - , technique : Technique - , activeTechnique : ActiveTechnique - , fullActiveTechnique : FullActiveTechnique - , val directive : Directive - , oldDirective : Option[Directive] - , workflowEnabled : Boolean - , onSuccessCallback : (Either[Directive,ChangeRequestId]) => JsCmd = { (Directive) => Noop } - , onMigrationCallback : (Directive, Option[Directive]) => JsCmd - , onFailureCallback : () => JsCmd = { () => Noop } - , isADirectiveCreation : Boolean = false + htmlId_policyConf : String + , technique : Technique + , activeTechnique : ActiveTechnique + , fullActiveTechnique : FullActiveTechnique + , val directive : Directive + , oldDirective : Option[Directive] + , workflowEnabled : Boolean + , globalMode : GlobalPolicyMode + , onSuccessCallback : (Either[Directive,ChangeRequestId]) => JsCmd = { (Directive) => Noop } + , onMigrationCallback : (Directive, Option[Directive]) => JsCmd + , onFailureCallback : () => JsCmd = { () => Noop } + , isADirectiveCreation : Boolean = false , onRemoveSuccessCallBack : () => JsCmd = { () => Noop } ) extends DispatchSnippet with Loggable { @@ -122,8 +127,9 @@ class DirectiveEditForm( private[this] val woChangeRequestRepo = RudderConfig.woChangeRequestRepository private[this] val roChangeRequestRepo = RudderConfig.roChangeRequestRepository private[this] val techniqueRepo = RudderConfig.techniqueRepository - private[this] val roRuleRepo = RudderConfig.roRuleRepository - private[this] val roRuleCategoryRepo = RudderConfig.roRuleCategoryRepository + private[this] val roRuleRepo = RudderConfig.roRuleRepository + private[this] val roRuleCategoryRepo = RudderConfig.roRuleCategoryRepository + private[this] val configService = RudderConfig.configService private[this] val htmlId_save = htmlId_policyConf + "Save" private[this] val parameterEditor = { @@ -131,12 +137,12 @@ class DirectiveEditForm( case Full(pe) => pe case Empty => { val errMsg = "Can not initialize the parameter editor for Directive %s " + - "(template %s). No error returned" + "(template %s). No error returned" throw new IllegalArgumentException(errMsg.format(directive.id, technique.id)) } case Failure(m, _, _) => { val errMsg = "Can not initialize the parameter editor for Directive %s " + - "(template %s). Error message: %s" + "(template %s). Error message: %s" throw new IllegalArgumentException(errMsg.format(directive.id, technique.id, m)) } } @@ -207,7 +213,7 @@ class DirectiveEditForm( val agentCompEmpty : NodeSeq = Can be used on any agent. - + technique.compatible match { case None => (osCompEmpty,agentCompEmpty) @@ -226,7 +232,7 @@ class DirectiveEditForm( case agent => {agent.mkString(", ")} - + } (osComp,agentComp) } @@ -272,6 +278,7 @@ class DirectiveEditForm( "#shortDescriptionField" #> piShortDescription.toForm_! & "#longDescriptionField" #> piLongDescription.toForm_! & "#priority" #> piPriority.toForm_! & + "#policyModes" #> policyModes.toForm_! & "#version" #> versionSelect.toForm_! & "#migrate" #> migrateButton(directiveVersion.is,"Migrate") & "#parameters" #> parameterEditor.toFormNodeSeq & @@ -396,28 +403,25 @@ class DirectiveEditForm( private[this] val piPriority = new WBSelectObjField( - "Priority:" + "Priority" , (0 to 10).map(i => (i, i.toString)) , defaultValue = directive.priority ) { override val displayHtml =
Priority determines which unique Directive will be applied.
+Unique Directives can be applied only once (ie. Time Settings), so only the highest priority will be appllied.
+Highest Priority is 0.
++ Currrent global settings do not allow this mode to be overriden on a per-directive bases. You may change this in Settings, + or contact your Rudder administrator about this. +
+ } + private[this] val policyModes = { + val globalPolicyModeName = configService.rudder_policy_mode_name().getOrElse("error").toString + val policyName = directive.policyMode match { + case None => globalPolicyModeName + case _ => directive.policyMode.getOrElse("error").toString + } + val l = Seq(None -> s"Use global default mode (currently ${globalPolicyModeName})", Some(Enforce) -> "Override to Enforce", Some(Verify) -> "Override to Audit") + new WBSelectObjField( + "Policy mode" + , l + , defaultValue = directive.policyMode + ) { + override val displayHtml = +Configuration rules in Rudder can operate in one of two modes:
++ By default all nodes and all directives operate in the global default mode defined in + Settings, which is currently {globalPolicyModeName}. +
+ {globalOverrideText} +This mode is an override applied to this directive. You can change it in the directive's settings.
") + case (Always,None) => + val expl = """This mode is the globally defined default. You can change it in settings.
You can also override it on this directive in the directive's settings.
""" + (globalMode.mode, expl) + case (Unoverridable,_) => + (globalMode.mode, "This mode is the globally defined default. You can change it in Settings.
") + } + val tooltipId = Helpers.nextFuncName - [{directive.techniqueVersion.toString}] {directive.name} + [BADGE][{directive.techniqueVersion.toString}] {directive.name} { + if(isAssignedTo <= 0) { } else { @@ -251,6 +273,7 @@ object DisplayDirectiveTree extends Loggable { } } ++ + Script(JsRaw(s"""$$('#badge-apm-${tooltipId}').replaceWith(createBadgeAgentPolicyMode('directive',"${policyMode}", "${explanation.toString()}"))""")) ++ deprecated ++ editButton ++This mode is an override applied to this node. You can change it in the node settings.
") + case (Always,None) => + val expl = """This mode is the globally defined default. You can change it in settings.
You can also override it on this node in the node's settings.
""" + (globalMode.mode, expl) + case (Unoverridable,_) => + (globalMode.mode, "This mode is the globally defined default. You can change it in Settings.
") + } + ) + + case None => + None + } val deleteButton : NodeSeq= { sm.node.main.status match { @@ -366,6 +398,12 @@ $$("#${detailsId}").bind( "show", function(event, ui) {This mode is an override applied to this node. You can change it in the node's settings.
") + case (Always,_) => + val expl = """This mode is the globally defined default. You can change it in settings.
You can also override it on this node in the node's settings.
""" + (node.policyMode.getOrElse(globalMode.mode), expl) + case (Unoverridable,_) => + (globalMode.mode, "This mode is the globally defined default. You can change it in Settings.
") + } + val optCallback = { callback.map(cb => ("callback", AnonFunc("displayCompliance", ajaxCall(JsVar("displayCompliance"), s => { @@ -246,6 +280,8 @@ case class NodeLine ( , ( "osName") -> S.?(s"os.name.${node.osDetails.os.name}") , ( "osVersion" -> node.osDetails.version.value) , ( "servicePack" -> node.osDetails.servicePack.getOrElse("N/A")) + , ( "agentPolicyMode" -> policyMode.toString) + , ( "explanation" -> explanation.toString) , ( "lastReport" -> lastReportValue ) ) } diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/HomePage.scala b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/HomePage.scala index 30b6d66d8e..a992128b37 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/HomePage.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/HomePage.scala @@ -97,7 +97,7 @@ case class GreenChart (value : Int) extends ComplianceLevelPieChart{ case class BlueChart (value : Int) extends ComplianceLevelPieChart{ val label = "Good (> 75%)" - val color = "#B2DE5B" + val color = "#9bc832" } case class OrangeChart (value : Int) extends ComplianceLevelPieChart{ diff --git a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/administration/PropertiesManagement.scala b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/administration/PropertiesManagement.scala index e839bdaa81..b793e2bab3 100644 --- a/rudder-web/src/main/scala/com/normation/rudder/web/snippet/administration/PropertiesManagement.scala +++ b/rudder-web/src/main/scala/com/normation/rudder/web/snippet/administration/PropertiesManagement.scala @@ -63,6 +63,7 @@ import com.normation.rudder.reports.SyslogProtocol import com.normation.rudder.reports.GlobalComplianceMode import com.normation.rudder.web.components.popup.ModificationValidationPopup.Enable import com.normation.rudder.domain.appconfig.FeatureSwitch._ +import com.normation.rudder.web.components.AgentPolicyModeEditForm /** * This class manage the displaying of user configured properties. @@ -87,6 +88,7 @@ class PropertiesManagement extends DispatchSnippet with Loggable { case "workflow" => workflowConfiguration case "denyBadClocks" => cfserverNetworkConfiguration case "cfagentSchedule" => (xml) => cfagentScheduleConfiguration + case "agentPolicyMode" => (xml) => agentPolicyModeConfiguration case "complianceMode" => (xml) => complianceModeConfiguration case "cfengineGlobalProps" => cfengineGlobalProps case "loggingConfiguration" => loggingConfiguration @@ -557,7 +559,9 @@ class PropertiesManagement extends DispatchSnippet with Loggable { , globalMode ) } - + val agentPolicyModeEditForm = { + new AgentPolicyModeEditForm() + } def getSchedule() : Box[AgentRunInterval] = { for { starthour <- configService.agent_run_start_hour @@ -589,6 +593,7 @@ class PropertiesManagement extends DispatchSnippet with Loggable { } def cfagentScheduleConfiguration = agentScheduleEditForm.cfagentScheduleConfiguration + def agentPolicyModeConfiguration = agentPolicyModeEditForm.cfagentPolicyModeConfiguration def complianceModeConfiguration = complianceModeEditForm.complianceModeConfiguration def cfengineGlobalProps = { xml : NodeSeq => 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 6afa04ae3b..8f29b74c6c 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.domain.policies.GlobalPolicyMode /** * Snippet for managing the System and Active Technique libraries. @@ -86,9 +87,10 @@ class DirectiveManagement extends DispatchSnippet with Loggable { val getRules = () => RudderConfig.roRuleRepository.getAll() val uuidGen = RudderConfig.stringUuidGenerator val treeUtilService = RudderConfig.jsTreeUtilService + private[this] val configService = RudderConfig.configService def dispatch = { - RudderConfig.configService.rudder_workflow_enabled match { + configService.rudder_workflow_enabled match { case Full(workflowEnabled) => { case "head" => { _ => head(workflowEnabled) } @@ -171,8 +173,8 @@ class DirectiveManagement extends DispatchSnippet with Loggable { def displayDirectiveLibrary(workflowEnabled: Boolean): NodeSeq = { (Directives are displayed in the tree of - - Active Techniques - , - grouped by categories.
-Additional Techniques may be available through the - - Techniques screen - . -
-+ Directives are displayed in the tree of + + Active Techniques + , grouped by categories. +
+Additional Techniques may be available through the + + Techniques screen + . +
+Supported operating systems: {comp.os.mkString(", ")}
- } } ++ { - if (comp.agents.isEmpty) { - NodeSeq.Empty - } else { -Supported agents: {comp.agents.mkString(", ")}
- } } - } & - "#techniqueDescription" #> technique.description & - "#techniqueLongDescription" #> technique.longDescription & - "#isSingle *" #> showIsSingle(technique) & - "#techniqueVersion *+" #> showVersions(fullActiveTechnique, validTechniqueVersions, workflowEnabled) + /* + * We want to filter technique to only show the one + * with registered acceptation date time. + * Also sort by version, reverse + */ + val validTechniqueVersions = fullActiveTechnique.techniques.map { case(v, t) => + fullActiveTechnique.acceptationDatetimes.get(v) match { + case Some(timeStamp) => Some((v, t, timeStamp)) + case None => + logger.error("Inconsistent Technique version state for Technique with ID '%s' and its version '%s': ".format(fullActiveTechnique.techniqueName, v.toString) + + "that version was not correctly registered into Rudder and can not be use for now.") + logger.info("A workaround is to remove that version manually from Rudder (move the directory for that version of the Technique out " + + "of your configuration-repository directory (for example in /tmp) and 'git commit' the modification), " + + "reload the Technique Library, then add back the version back (move it back at its place, 'git add' the directory, 'git commit' the" + + "modification), and reload again the Technique Library.") + + None + } + }.toSeq.flatten.sortBy( _._1 ) + + "#directiveIntro " #> { + currentDirectiveSettingForm.is.map { piForm => + (".directive *" #> piForm.directive.name) + } + } & + "#techniqueName" #> technique.name & + "#compatibility" #> technique.compatible.map { comp => + { if(comp.os.isEmpty) { + NodeSeq.Empty + } else { +Supported operating systems: {comp.os.mkString(", ")}
+ } } ++ { + if (comp.agents.isEmpty) { + NodeSeq.Empty + } else { +Supported agents: {comp.agents.mkString(", ")}
+ } } + } & + "#techniqueDescription" #> technique.description & + "#techniqueLongDescription" #> technique.longDescription & + "#isSingle *" #> showIsSingle(technique) & + "#techniqueVersion *+" #> showVersions(fullActiveTechnique, validTechniqueVersions, workflowEnabled) } }) } @@ -391,25 +403,36 @@ class DirectiveManagement extends DispatchSnippet with Loggable { } private[this] def newDirective(technique: Technique, activeTechnique: FullActiveTechnique, workflowEnabled: Boolean) = { - val allDefaults = techniqueRepository.getTechniquesInfo.directivesDefaultNames - val directiveDefaultName = allDefaults.get(technique.id.toString).orElse(allDefaults.get(technique.id.name.value)).getOrElse(technique.name) - val directive = - Directive( - DirectiveId(uuidGen.newUuid) - , technique.id.version - , Map() - , directiveDefaultName - , "" - , None - , "" - , 5 - , true - ) - updateDirectiveSettingForm(activeTechnique, directive,None, workflowEnabled, true) - //Update UI - Replace(htmlId_policyConf, showDirectiveDetails) & - SetHtml(html_techniqueDetails, NodeSeq.Empty) & - JsRaw("""createTooltip();""") + configService.rudder_global_policy_mode() match { + case Full(globalMode) => + val allDefaults = techniqueRepository.getTechniquesInfo.directivesDefaultNames + val directiveDefaultName = allDefaults.get(technique.id.toString).orElse(allDefaults.get(technique.id.name.value)).getOrElse(technique.name) + val directive = + Directive( + DirectiveId(uuidGen.newUuid) + , technique.id.version + , Map() + , directiveDefaultName + , "" + , None + , "" + , 5 + , true + ) + updateDirectiveSettingForm(activeTechnique, directive,None, workflowEnabled, true, globalMode) + //Update UI + Replace(htmlId_policyConf, showDirectiveDetails) & + SetHtml(html_techniqueDetails, NodeSeq.Empty) & + JsRaw("""createTooltip();""") + case eb:EmptyBox => + val fail = eb ?~! "Could not get global policy mode while creating new Directive" + logger.error(fail.messageChain) + val errorHtml = +{fail.messageChain}
+This "+ kind +" is in "+ policyName +" mode.
"+ + ""+ explanation +"
"+ + "Configure the networks from which nodes are allowed - to connect to the Rudder policy servers to get their updated - configuration policy.
-- You can add as many networks as you want, the expected - format is: NetworkIP/mask, for example - "42.42.0.0/16". -
-Configure the networks from which nodes are allowed + to connect to the Rudder policy servers to get their updated + configuration policy.
++ You can add as many networks as you want, the expected + format is: NetworkIP/mask, for example + "42.42.0.0/16". +
+If enabled, prompt users to enter a message explaining the reason for each configuration change they make.
- These messages will be stored in each Event log and as the commit message for the underlying git repository in
+ If enabled, prompt users to enter a message explaining the reason for each configuration change they make.
+ These messages will be stored in each Event log and as the commit message for the underlying git repository in
+
+
If enabled, all changes to configuration (Directives, Rules, Groups and Parameters) will be submitted for validation via a Change Request.
-A new Change Request will enter the "Pending validation" status, then can be moved to "Pending deployment" (approved but not yet deployed) or "Deployed" (approved and deployed) statuses.
-Only users with the "validator" or "deployer" roles are authorized to perform these steps (see /opt/rudder/etc/rudder-users.xml).
-
-If disabled, all changes to configuration will be immediately deployed.
+ If enabled, all changes to configuration (Directives, Rules, Groups and Parameters) will be submitted for validation via a Change Request.
+ A new Change Request will enter the "Pending validation" status, then can be moved to "Pending deployment" (approved but not yet deployed) or "Deployed" (approved and deployed) statuses.
+
+ Only users with the "validator" or "deployer" roles are authorized to perform these steps (see /opt/rudder/etc/rudder-users.xml). +
++ If disabled, all changes to configuration will be immediately deployed. +
Every time Rudder modifies a file (by file editing or copying from a remote source), a copy of the overwritten file is kept under /var/rudder/modified-files/.
-Also, the full output from each agent run is stored in a file under /var/rudder/cfengine-community/outputs/.
-These files are automatically removed to save on disk space. You can configure the retention time (Time To Live) they are kept for here.
Every time Rudder modifies a file (by file editing or copying from a remote source), a copy of the overwritten file is kept under /var/rudder/modified-files/.
++ Also, the full output from each agent run is stored in a file under /var/rudder/cfengine-community/outputs/. + These files are automatically removed to save on disk space. You can configure the retention time (Time To Live) they are kept for here. +
All nodes in Rudder send reports via syslog to this Rudder root server. These logs are stored in an SQL database in order to determine compliance information displayed in this web interface. However, it can be useful to also store this information in a plain text log file, for example for statistics or debugging purposes. The option below enables this.
To help the Rudder team continue to improve this software day after day, we are running a survey to collect usage statistics.
+These statistics are submitted anonymously, and include overall statistics about your instance of Rudder
(number of Rules, Directives, Nodes, etc). No potentially-sensitive data is included
(only stock Rudder-provided techniques are examined, no hostnames, etc).
- We highly value your privacy, as we do our own, so we will never share individual submissions (only globally compiled statistics).
- If you want to check the information that is sent, just run "/opt/rudder/bin/rudder-metrics-reporting -v" on your Rudder server. This won't send any information without your consent.
+ We highly value your privacy, as we do our own, so we will never share individual submissions (only globally compiled statistics)
+
+ If you want to check the information that is sent, just run "/opt/rudder/bin/rudder-metrics-reporting -v" on your Rudder server. This won't send any information without your consent. +
+This information is very valuable to the development team, as it helps us focus on the features that matter most and better understand what our users care about. Please consider participating in the survey! +
In Rules table, we display a graph for each Rule showing it's activity (number of repaired reports).
+Unfortunately, some browsers (especially Firefox) have trouble displaying them and make Rule pages almost unusable.
+If you experience slow loading of Rules pages, you can disable this feature here.
API response used to send data that may not be sent back to the API for modification. Parameter to enable a directive is 'enabled', but API response was using 'isEnabled' for that parameter, so you had to handle this case before sending data. We have harmonized response and parameters (in this ). @@ -424,11 +460,14 @@
Clear cached data. This will trigger a full policy update, and regenerate all promise files.
@@ -483,12 +525,14 @@Groups in Rudder can be static (fixed list of nodes) or dynamic (the list of nodes is built from a search query).
-To take into account new nodes and changes to their inventory, dynamic groups must be reloaded regularly.
-Currently, Rudder will automatically do this reload every 5 minutes (see /opt/rudder/etc/rudder-web.properties).
-
Groups in Rudder can be static (fixed list of nodes) or dynamic (the list of nodes is built from a search query).
+To take into account new nodes and changes to their inventory, dynamic groups must be reloaded regularly.
+Currently, Rudder will automatically do this reload every 5 minutes (see /opt/rudder/etc/rudder-web.properties).
Techniques in Rudder are read from the filesystem (in /var/rudder/configuration-repository/techniques).
-To take into account new Techniques and changes, the Technique library must be updated regularly.
-Currently, Rudder will automatically do this update every 5 minutes (see /opt/rudder/etc/rudder-web.properties).
-
Techniques in Rudder are read from the filesystem (in /var/rudder/configuration-repository/techniques).
+To take into account new Techniques and changes, the Technique library must be updated regularly.
+Currently, Rudder will automatically do this update every 5 minutes (see /opt/rudder/etc/rudder-web.properties).
+ Configuration rules in Rudder can operate in one of two modes: +
++ This setting is a global switch and will apply to all nodes and all directives as the default mode. You may also override this mode on a per-node and per-directive basis. +
++ By default all nodes and all directives operate in the global mode defined in Settings + , which is currently {{globalConfiguration.policyMode}}. +
+By default, the agent runs on all nodes every 5 minutes.
This high frequency enables fast response times to apply changes and state @@ -29,8 +33,8 @@
The current global setting is to run every {{getIntervalValue(globalRun.interval)}}, starting at {{(format2Digits(globalRun.startHour))}}:{{(format2Digits(globalRun.startMinute))}}, with a maximum delay after scheduled run time (random interval) of {{(format2Digits(globalRun.splayHour))}}:{{(format2Digits(globalRun.splayMinute))}}.
You may override this global setting just for this node below: