Skip to content

Commit

Permalink
Fixes #5796: Make syslog transport configurable from web interface
Browse files Browse the repository at this point in the history
  • Loading branch information
VinceMacBuche committed Jun 11, 2015
1 parent 6a1dd0a commit 9daf604
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 0 deletions.
@@ -0,0 +1,41 @@
###############################################################################
# Copyright 2015 Normation SAS
###############################################################################
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero GPL v3, 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 Affero GPL v3
# licence, 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.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/agpl.html>.
#
###############################################################################

# Create the syslog protocotl portperty with value 'TCP', a different value from new rudder installation
# By doing so, we keep the same behavior as before

dn: propertyName=rudder_syslog_protocol,ou=Application Properties,cn=rudder-
configuration
objectClass: property
objectClass: top
propertyName: rudder_syslog_protocol
propertyValue: TCP
11 changes: 11 additions & 0 deletions rudder-core/src/main/resources/ldap/bootstrap.ldif
Expand Up @@ -323,3 +323,14 @@ description: Default inform message put in header of managed files by Rudder
overridable: TRUE
parameterValue: ### Managed by Rudder, edit with care ###

dn: ou=Application Properties,cn=rudder-configuration
objectClass: organizationalUnit
objectClass: top
ou: Application Properties

dn: propertyName=rudder_syslog_protocol,ou=Application Properties,cn=rudder-
configuration
objectClass: property
objectClass: top
propertyName: rudder_syslog_protocol
propertyValue: UDP
Expand Up @@ -279,6 +279,11 @@ final case object ModifyAgentRunStartMinuteEventType extends ModifyGlobalPropert
val propertyName = "Agent run start minute"
}

final case object ModifyRudderSyslogProtocolEventType extends ModifyGlobalPropertyEventType {
def serialize = "RudderSyslogProtocolModified"
val propertyName = "Rudder syslog protocol"
}

/**
* List of event generating a modification of promises
*/
Expand Down
Expand Up @@ -29,6 +29,7 @@ object ModifyGlobalPropertyEventLogsFilter {
ModifyAgentRunSplaytimeEventType ::
ModifyAgentRunStartHourEventType ::
ModifyAgentRunStartMinuteEventType ::
ModifyRudderSyslogProtocolEventType ::
Nil

final val eventList : List[EventLogFilter] =
Expand Down
Expand Up @@ -140,3 +140,15 @@ class AgentRunIntervalServiceImpl(

}

sealed trait SyslogProtocol {
def value : String
}

object SyslogTCP extends SyslogProtocol {
val value = "TCP"
}

object SyslogUDP extends SyslogProtocol {
val value = "UDP"
}

Expand Up @@ -57,6 +57,7 @@ import com.normation.rudder.reports.ComplianceMode
import com.normation.rudder.reports.FullCompliance
import com.normation.rudder.reports.ChangesOnly
import com.normation.rudder.reports.AgentRunInterval
import com.normation.rudder.reports.SyslogProtocol

trait SystemVariableService {
def getGlobalSystemVariables(): Box[Map[String, Variable]]
Expand Down Expand Up @@ -101,6 +102,7 @@ class SystemVariableServiceImpl(
, getCfengineOutputsTtl : () => Box[Int]
, getStoreAllCentralizedLogsInFile: () => Box[Boolean]
, getSendMetrics : () => Box[Option[Boolean]]
, getSyslogProtocol : () => Box[SyslogProtocol]
) extends SystemVariableService with Loggable {

val varToolsFolder = systemVariableSpecService.get("TOOLS_FOLDER").toVariable().copyWithSavedValue(toolsFolder)
Expand Down Expand Up @@ -136,6 +138,7 @@ class SystemVariableServiceImpl(
val skipIdentify = getProp("SKIPIDENTIFY", getSkipIdentify)
val modifiedFilesTtl = getProp("MODIFIED_FILES_TTL", getModifiedFilesTtl)
val cfengineOutputsTtl = getProp("CFENGINE_OUTPUTS_TTL", getCfengineOutputsTtl)
val reportProtocol = getProp("RUDDER_SYSLOG_PROTOCOL", getSyslogProtocol)

val sendMetricsValue = if (getSendMetrics().getOrElse(None).getOrElse(false)) {
"yes"
Expand Down Expand Up @@ -177,6 +180,7 @@ class SystemVariableServiceImpl(
cfengineOutputsTtl ::
storeAllCentralizedLogsInFile ::
varSendMetrics ::
reportProtocol ::
Nil
vars.map(v => (v.spec.name,v)).toMap
}
Expand Down
2 changes: 2 additions & 0 deletions rudder-web/src/main/resources/eventLogTypeNames.properties
Expand Up @@ -57,4 +57,6 @@ rudder.log.eventType.names.AgentRunIntervalModified=Property 'Agent run interval
rudder.log.eventType.names.AgentRunSplaytimeModified=Property 'Agent run splaytime' modified
rudder.log.eventType.names.AgentRunStartHourModified=Property 'Agent run start hour' modified
rudder.log.eventType.names.AgentRunStartMinuteModified=Property 'Agent run start minute' modified
rudder.log.eventType.names.RudderSyslogProtocolModified=Property 'Rudder syslog protocol' modified


Expand Up @@ -1267,6 +1267,7 @@ object RudderConfig extends Loggable {
, configService.cfengine_outputs_ttl _
, configService.rudder_store_all_centralized_logs_in_file _
, configService.send_server_metrics _
, configService.rudder_syslog_protocol _
)
private[this] lazy val rudderCf3PromisesFileWriterService = new RudderCf3PromisesFileWriterServiceImpl(
techniqueRepositoryImpl,
Expand Down
Expand Up @@ -56,6 +56,8 @@ import com.normation.rudder.domain.eventlog.ModifyAgentRunIntervalEventType
import com.normation.rudder.domain.eventlog.ModifyAgentRunStartHourEventType
import com.normation.rudder.domain.eventlog.ModifyAgentRunStartMinuteEventType
import com.normation.rudder.domain.eventlog.ModifyAgentRunSplaytimeEventType
import com.normation.rudder.reports._
import com.normation.rudder.domain.eventlog.ModifyRudderSyslogProtocolEventType

/**
* A service that Read mutable (runtime) configuration properties
Expand Down Expand Up @@ -133,6 +135,11 @@ trait ReadConfigService {
*/
def send_server_metrics(): Box[Option[Boolean]]

/**
* Report protocol
*/
def rudder_syslog_protocol(): Box[SyslogProtocol]

}

/**
Expand Down Expand Up @@ -201,6 +208,11 @@ trait UpdateConfigService {

def set_rudder_compliance_heartbeatPeriod(frequency : Int, actor: EventActor, reason: Option[String]) : Box[Unit]

/**
* Report protocol
*/
def set_rudder_syslog_protocol(value : SyslogProtocol, actor : EventActor, reason: Option[String]): Box[Unit]

}

class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workflowUpdate: AsyncWorkflowInfo) extends ReadConfigService with UpdateConfigService with Loggable {
Expand Down Expand Up @@ -229,6 +241,7 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl
send.server.metrics=none
rudder.compliance.mode=${FullCompliance.name}
rudder.compliance.heartbeatPeriod=1
rudder.syslog.protocol=UDP
"""

val configWithFallback = configFile.withFallback(ConfigFactory.parseString(defaultConfig))
Expand Down Expand Up @@ -270,6 +283,10 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl
case _ => Some(false)
}

private[this] implicit def toSyslogProtocol(p: RudderWebProperty): SyslogProtocol = p.value.toLowerCase match {
case "TCP" => SyslogTCP
case _ => SyslogUDP
}
private[this] implicit def toString(p: RudderWebProperty): String = p.value

private[this] implicit def toUnit(p: Box[RudderWebProperty]) : Box[Unit] = p.map( _ => ())
Expand Down Expand Up @@ -392,4 +409,14 @@ class LDAPBasedConfigService(configFile: Config, repos: ConfigRepository, workfl
save("send_server_metrics",newVal,Some(info))
}


/**
* Report protocol
*/
def rudder_syslog_protocol(): Box[SyslogProtocol] = get("rudder_syslog_protocol")
def set_rudder_syslog_protocol(protocol : SyslogProtocol, actor : EventActor, reason: Option[String]): Box[Unit] = {
val info = ModifyGlobalPropertyInfo(ModifyRudderSyslogProtocolEventType,actor,reason)
save("rudder_syslog_protocol", protocol.value, Some(info))
}

}
Expand Up @@ -54,6 +54,9 @@ import com.normation.rudder.reports.ChangesOnly
import com.normation.rudder.web.components.AgentScheduleEditForm
import com.normation.rudder.reports.AgentRunInterval
import com.normation.rudder.web.components.ComplianceModeEditForm
import com.normation.rudder.reports.SyslogUDP
import com.normation.rudder.reports.SyslogTCP
import com.normation.rudder.reports.SyslogProtocol


/**
Expand Down Expand Up @@ -83,6 +86,7 @@ class PropertiesManagement extends DispatchSnippet with Loggable {
case "cfengineGlobalProps" => cfengineGlobalProps
case "loggingConfiguration" => loggingConfiguration
case "sendMetricsConfiguration" => sendMetricsConfiguration
case "networkProtocolSection" => networkProtocolSection
}


Expand Down Expand Up @@ -469,6 +473,63 @@ class PropertiesManagement extends DispatchSnippet with Loggable {
) apply (xml ++ Script(Run("correctButtons();") & check()))
}

def networkProtocolSection = { xml : NodeSeq =>
// initial values, updated on successfull submit
def networkForm(initValue : SyslogProtocol) = {
var initReportsProtocol = initValue
var reportProtocol = initValue
def check = {
val noChange = initReportsProtocol == reportProtocol
S.notice("updateNetworkProtocol","")
Run(s"""$$("#networkProtocolSubmit").button( "option", "disabled",${noChange});""")
}

def submit = {
val actor = CurrentUser.getActor
configService.set_rudder_syslog_protocol(reportProtocol,actor,None) match {
case Full(_) =>
// Update the initial value of the form
initReportsProtocol = reportProtocol
startNewPolicyGeneration
S.notice("updateNetworkProtocol","Network protocol options correctly updated")
check
case eb:EmptyBox =>
S.error("updateNetworkProtocol","Error when saving network protocol options")
Noop
}
}

val checkboxInitValue = initReportsProtocol == SyslogUDP

( "#reportProtocol" #> {
SHtml.ajaxCheckbox(
checkboxInitValue
, (newValue : Boolean) => {
reportProtocol = if (newValue) SyslogUDP else SyslogTCP
check
}
, ("id","reportProtocol")
)
} &
"#networkProtocolSubmit " #> {
SHtml.ajaxSubmit("Save changes", submit _)
}
)(xml ++ Script(Run("correctButtons();") & check))

}

configService.rudder_syslog_protocol match {
case Full(value) =>
networkForm(value)
case eb: EmptyBox =>
// We could not read current protocol, try repairing by setting protocol to UDP and warn user
val actor = CurrentUser.getActor
configService.set_rudder_syslog_protocol(SyslogUDP,actor,Some("Property automatically reset to 'UDP' due to an error"))
S.error("updateNetworkProtocol","Error when fetching 'Syslog protocol' property, Setting it to UDP")
networkForm(SyslogUDP)
}
}

val agentScheduleEditForm = new AgentScheduleEditForm(
getSchedule
, saveSchedule
Expand Down
Expand Up @@ -118,6 +118,33 @@ <h3>Security</h3>
</div>
</div>
<hr class="spacer" />
<div class="deca">
<h3>Protocol</h3>
<div class="lift:administration.PropertiesManagement.networkProtocolSection" id="networkProtocolForm">
<form class="lift:form.ajax">
<div class="wbBaseField">
<label for="reportProtocol" class="threeCol textight" style="font-weight:bold;width: 50%;">
<span >Use TCP in place of UDP (default) for syslog communication between node and servers:
<img src="/images/icInfo.png" style="padding-left:15px; margin:0; float:none" tooltipid="reportProtocolTooltip" title="" class="tooltipable" />
</span>
<div class="tooltipContent" id="reportProtocolTooltip">
Rudder uses syslog to transfer report messages from nodes to relay and servers.
<ul>
<li><b>UDP (default):</b> the syslog never stalls an a non responsive connection, which could also stale other services on the node which use the same syslog.</li>
<li><b>TCP:</b> Using TCP allows to minimize the loss in reports and the resulting compliance errors.</li>
</ul>
This settings is ignored on clients that don't support TCP (AIX, sysklogd, ...)
</div>
</label>
<input id="reportProtocol" type="text"/>
</div>
<hr class="spacer"/>
<input type="submit" value="[save]" id="networkProtocolSubmit"/>
<lift:Msg id="updateNetworkProtocol">[messages]</lift:Msg>
</form>
</div>
</div>
<hr class="spacer" />


</div>
Expand Down

0 comments on commit 9daf604

Please sign in to comment.