Skip to content

Commit

Permalink
Fixes #9950: Policy generation fails in 4.1 with 'kill: usage: kill […
Browse files Browse the repository at this point in the history
…-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]'
  • Loading branch information
fanf committed Jan 13, 2017
1 parent 222833b commit e897716
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 38 deletions.
Expand Up @@ -71,22 +71,35 @@ import net.liftweb.util.Helpers.tryo

/*
* Hooks are group in "set". We run all the hooks
* from the same set with the same set of parameters.
* from the same set with the same set of envVariables.
* The hooks are executed in the order of the list.
*/

final case class Hooks(basePath: String, hooksFile: List[String])
/**
* Hook parameters are pairs of environment variable name <=> value
* Hook env are pairs of environment variable name <=> value
*/
final case class HookParameter(name: String, value: String)
final case class HookParameters(values: List[HookParameter]) {
//shortcut to view parameters as a Map[String, String]
final case class HookEnvPair(name: String, value: String) {
def show = s"[${name}:${value}]"
}
final case class HookEnvPairs(values: List[HookEnvPair]) {
//shortcut to view envVariables as a Map[String, String]
def toMap = values.map(p => (p.name, p.value)).toMap

def add(other: HookEnvPairs) = HookEnvPairs(this.values ::: other.values)

/**
* Formatted string
* [key1:val1][key2:val2]...
*/
def show: String = values.map(_.show).mkString(" ")
}
object HookParameters {

object HookEnvPairs {
def toListPairs(values: (String, String)*) = values.map( p => HookEnvPair(p._1, p._2)).toList

def build( values: (String, String)*) = {
HookParameters(values.map( p => HookParameter(p._1, p._2)).toList)
HookEnvPairs(toListPairs(values:_*))
}
}

Expand Down Expand Up @@ -115,7 +128,7 @@ object RunHooks {
* - > 255: should not happen, but treated as reserved.
*
*/
def asyncRun(hooks: Hooks, parameters: HookParameters): Future[Box[Unit]] = {
def asyncRun(hooks: Hooks, hookParameters: HookEnvPairs, envVariables: HookEnvPairs): Future[Box[Unit]] = {
/*
* We can not use Future.fold, because it execute all scripts
* in parallele and then combine their results. Our semantic
Expand All @@ -127,9 +140,11 @@ object RunHooks {
val path = hooks.basePath + File.separator + nextHookName
previousFuture.flatMap {
case Full(()) =>
HooksLogger.debug(s"Run hook: '${path} ${parameters.values.mkString(" ")}'")
RunNuCommand.run(Cmd(path, Nil, parameters.toMap)).map { result =>
lazy val msg = s"Exit code=${result.code} for hook: '${path} ${parameters.values.mkString(" ")}'. \n Stdout: '${result.stdout}' \n Stderr: '${result.stderr}'"
HooksLogger.debug(s"Run hook: '${path}' with environment parameters: ${hookParameters.show}")
HooksLogger.trace(s"System environment variables: ${envVariables.show}")
val env = envVariables.add(hookParameters)
RunNuCommand.run(Cmd(path, Nil, env.toMap)).map { result =>
lazy val msg = s"Exit code=${result.code} for hook: '${path}' with environment variables: ${env.show}. \n Stdout: '${result.stdout}' \n Stderr: '${result.stderr}'"
HooksLogger.trace(s" -> results: ${msg}")
if( result.code <= 0 ) {
Full(())
Expand All @@ -142,7 +157,7 @@ object RunHooks {
Failure(msg)
}
} recover {
case ex: Exception => Failure(s"Exception when executing '${path} ${parameters.values.mkString(" ")}: ${ex.getMessage}")
case ex: Exception => Failure(s"Exception when executing '${path}' with environment variables: ${env.show}: ${ex.getMessage}")
}
case eb: EmptyBox => Future(eb)
}
Expand All @@ -166,13 +181,14 @@ object RunHooks {
*
*
*/
def syncRun(hooks: Hooks, parameters: HookParameters): Box[Unit] = {
def syncRun(hooks: Hooks, hookParameters: HookEnvPairs, envVariables: HookEnvPairs): Box[Unit] = {
try {
//cmdInfo is just for comments/log. We use "*" to synthetize
val cmdInfo = s"'${hooks.basePath}/* ${parameters.values.mkString(" ")}'"
val cmdInfo = s"'${hooks.basePath}' with environment parameters: ${hookParameters.show}"
HooksLogger.debug(s"Run hooks: ${cmdInfo}")
HooksLogger.trace(s"Hook environment variables: ${envVariables.show}")
val time_0 = System.currentTimeMillis
val res = Await.result(asyncRun(hooks, parameters), Duration.Inf)
val res = Await.result(asyncRun(hooks, hookParameters, envVariables), Duration.Inf)
HooksLogger.debug(s"Done in ${System.currentTimeMillis - time_0} ms: ${cmdInfo}")
res
} catch {
Expand Down
Expand Up @@ -90,8 +90,8 @@ import com.normation.rudder.domain.reports.NodeModeConfig
import com.normation.rudder.reports.HeartbeatConfiguration
import org.joda.time.format.DateTimeFormatter
import com.normation.rudder.hooks.RunHooks
import com.normation.rudder.hooks.HookParameters
import com.normation.rudder.hooks.HookParameter
import com.normation.rudder.hooks.HookEnvPairs
import com.normation.rudder.hooks.HookEnvPair
import ch.qos.logback.core.db.DataSourceConnectionSource
import com.normation.rudder.datasources.DataSourceUpdateCallbacks
import com.normation.rudder.datasources.DataSourceUpdateCallbacks
Expand All @@ -117,11 +117,15 @@ trait PromiseGenerationService extends Loggable {

val generationTime = new DateTime(initialTime)
val rootNodeId = Constants.ROOT_POLICY_SERVER_ID
//we need to add the current environment variables to the script context
//plus the script environment variables used as script parameters
import scala.collection.JavaConverters._
val systemEnv = HookEnvPairs.build(System.getenv.asScala.toSeq:_*)

val result = for {
//fetch all - yep, memory is cheap... (TODO: size of that for 1000 nodes, 100 rules, 100 directives, 100 groups ?)
preHooks <- RunHooks.getHooks(HOOKS_D + "/policy-generation-started")
_ <- RunHooks.syncRun(preHooks, HookParameters.build { ("RUDDER_GENERATION_DATETIME", generationTime.toString) } )
_ <- RunHooks.syncRun(preHooks, HookEnvPairs.build( ("RUDDER_GENERATION_DATETIME", generationTime.toString) ), systemEnv)
timeRunPreGenHooks = (System.currentTimeMillis - initialTime)
_ = logger.debug(s"Post-policy-generation hooks ran in ${timeRunPreGenHooks} ms")

Expand Down Expand Up @@ -229,13 +233,16 @@ trait PromiseGenerationService extends Loggable {
postHooksTime = System.currentTimeMillis
postHooks <- RunHooks.getHooks(HOOKS_D + "/policy-generation-finished")
updatedNodeIds = updatedNodeConfigs.keySet.map( _.value )
_ <- RunHooks.syncRun(postHooks, HookParameters.build(
("RUDDER_GENERATION_DATETIME", generationTime.toString())
, ("RUDDER_END_GENERATION_DATETIME", new DateTime(postHooksTime).toString) //what is the most alike a end time
, ("RUDDER_NODEIDS", updatedNodeIds.mkString(" "))
, ("RUDDER_NUMBER_NODES_UPDATED", updatedNodeIds.size.toString)
, ("RUDDER_ROOT_POLICY_SERVER_UPDATED", if(updatedNodeIds.contains("root")) "0" else "1" )
)
_ <- RunHooks.syncRun(
postHooks
, HookEnvPairs.build(
("RUDDER_GENERATION_DATETIME", generationTime.toString())
, ("RUDDER_END_GENERATION_DATETIME", new DateTime(postHooksTime).toString) //what is the most alike a end time
, ("RUDDER_NODEIDS", updatedNodeIds.mkString(" "))
, ("RUDDER_NUMBER_NODES_UPDATED", updatedNodeIds.size.toString)
, ("RUDDER_ROOT_POLICY_SERVER_UPDATED", if(updatedNodeIds.contains("root")) "0" else "1" )
)
, systemEnv
)
timeRunPostGenHooks = (System.currentTimeMillis - postHooksTime)
_ = logger.debug(s"Post-policy-generation hooks ran in ${timeRunPostGenHooks} ms")
Expand Down
Expand Up @@ -82,7 +82,7 @@ import net.liftweb.json.Printer
import com.normation.rudder.domain.policies.GlobalPolicyMode
import scala.language.postfixOps
import com.normation.rudder.hooks.RunHooks
import com.normation.rudder.hooks.HookParameters
import com.normation.rudder.hooks.HookEnvPairs
import com.normation.rudder.hooks.HooksLogger

/**
Expand Down Expand Up @@ -192,6 +192,11 @@ class Cf3PromisesFileWriterServiceImpl(
* - and finally, move everything to each node rules directory
*/

//we need to add the current environment variables to the script context
//plus the script environment variables used as script parameters
import scala.collection.JavaConverters._
val systemEnv = HookEnvPairs.build(System.getenv.asScala.toSeq:_*)

for {
configAndPaths <- calculatePathsForNodeConfigurations(interestingNodeConfigs, rootNodeId, allNodeConfigs, newPostfix, backupPostfix)
pathsInfo = configAndPaths.map { _.paths }
Expand All @@ -217,12 +222,15 @@ class Cf3PromisesFileWriterServiceImpl(
preMvHooks <- sequencePar(configAndPaths) { agentNodeConfig =>
val timeHooks = System.currentTimeMillis
val nodeId = agentNodeConfig.config.nodeInfo.node.id.value
val res = RunHooks.syncRun(nodePreMvHooks, HookParameters.build(
("RUDDER_GENERATION_DATETIME", generationTime.toString)
, ("RUDDER_NODEID", nodeId)
, ("RUDDER_NEXT_POLICIES_DIRECTORY", agentNodeConfig.paths.newFolder)
, ("RUDDER_AGENT_TYPE", agentNodeConfig.agentType.tagValue)
)
val res = RunHooks.syncRun(
nodePreMvHooks
, HookEnvPairs.build(
("RUDDER_GENERATION_DATETIME", generationTime.toString)
, ("RUDDER_NODEID", nodeId)
, ("RUDDER_NEXT_POLICIES_DIRECTORY", agentNodeConfig.paths.newFolder)
, ("RUDDER_AGENT_TYPE", agentNodeConfig.agentType.tagValue)
)
, systemEnv
)
HooksLogger.trace(s"Run post-generation pre-move hooks for node '${nodeId}' in ${System.currentTimeMillis - timeHooks} ms")
res
Expand All @@ -232,12 +240,15 @@ class Cf3PromisesFileWriterServiceImpl(
postMvHooks <- sequencePar(configAndPaths) { agentNodeConfig =>
val timeHooks = System.currentTimeMillis
val nodeId = agentNodeConfig.config.nodeInfo.node.id.value
val res = RunHooks.syncRun(nodePostMvHooks, HookParameters.build(
("RUDDER_GENERATION_DATETIME", generationTime.toString)
, ("RUDDER_NODEID", nodeId)
, ("RUDDER_POLICIES_DIRECTORY", agentNodeConfig.paths.baseFolder)
, ("RUDDER_AGENT_TYPE", agentNodeConfig.agentType.tagValue)
)
val res = RunHooks.syncRun(
nodePostMvHooks
, HookEnvPairs.build(
("RUDDER_GENERATION_DATETIME", generationTime.toString)
, ("RUDDER_NODEID", nodeId)
, ("RUDDER_POLICIES_DIRECTORY", agentNodeConfig.paths.baseFolder)
, ("RUDDER_AGENT_TYPE", agentNodeConfig.agentType.tagValue)
)
, systemEnv
)
HooksLogger.trace(s"Run post-generation post-move hooks for node '${nodeId}' in ${System.currentTimeMillis - timeHooks} ms")
res
Expand Down
18 changes: 18 additions & 0 deletions rudder-web/src/main/resources/logback.xml
Expand Up @@ -365,6 +365,24 @@ along with Rudder. If not, see <http://www.gnu.org/licenses/>.
-->
<logger name="com.normation.rudder.services.quicksearch" level="info" />



<!--
Hooks
==========
Information about hooks execution.
This log allow to see what hooks are executed.
Debug level will display hooks with their parameter (may be quite noisy when there
is a lot of nodes implied). Trace add system information (like environment variables).
-->
<logger name="hooks" level="info" additivity="false">
<appender-ref ref="OPSLOG" />
<!-- comment the following appender if you don't want to have logs about report in both stdout and opslog -->
<appender-ref ref="STDOUT" />
</logger>


<!--
Datasource
==========
Expand Down

0 comments on commit e897716

Please sign in to comment.