Skip to content

Commit

Permalink
Work in progress
Browse files Browse the repository at this point in the history
  • Loading branch information
fanf committed Jun 8, 2017
1 parent 85df9c0 commit 909bae9
Show file tree
Hide file tree
Showing 10 changed files with 449 additions and 69 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
*************************************************************************************
* Copyright 2017 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 <http://www.gnu.org/licenses/>.
*
*************************************************************************************
*/

package com.normation.rudder.services.policies.write

import org.apache.commons.io.FileUtils
import scala.io.Codec
import java.io.File
import net.liftweb.common.Box
import net.liftweb.util.Helpers.tryo
import com.normation.inventory.domain.AgentType
import com.normation.inventory.domain.COMMUNITY_AGENT
import com.normation.inventory.domain.NOVA_AGENT
import com.normation.utils.Control.sequence
import net.liftweb.common.Full
import com.normation.inventory.domain.DSC_AGENT

/*
* This file contain agent-type specific logic used during the policy
* writing process, mainly:
* - specific files (like expected_reports.csv for CFEngine-based agent)
* - specific format for "bundle" sequence.
*/

//containser for agent specific file written during policy generation
final case class AgentSpecificFile(
path: String
)

// does that implementation knows something about the current agent type
trait AgentSpecificGenerationHandle {
def handle(agentType: AgentType): Boolean
}


// specific generic (i.e non bundle order linked) system variable
// todo - need to plug in systemvariablespecservice
// idem for the bundle seq

//write what must be written for the given configuration
trait WriteAgentSpecificFiles {
def write(cfg: AgentNodeWritableConfiguration): Box[List[AgentSpecificFile]]
}


// the pipeline of processing for the specific writes
object WriteAllAgentSpecificFiles extends WriteAgentSpecificFiles {

/**
* Ordered list of handlers
*/
var pipeline: List[WriteAgentSpecificFiles with AgentSpecificGenerationHandle] = {
CFEngineAgentSpecificGeneration :: DscAgentSpecificGeneration :: Nil
}

override def write(cfg: AgentNodeWritableConfiguration): Box[List[AgentSpecificFile]] = {
(sequence(pipeline) { handler =>
if(handler.handle(cfg.agentType)) {
handler.write(cfg)
} else {
Full(Nil)
}
}).map( _.flatten.toList)
}

}


trait AgentSpecificGeneration extends WriteAgentSpecificFiles with AgentSpecificGenerationHandle

object CFEngineAgentSpecificGeneration extends AgentSpecificGeneration {
val GENEREATED_CSV_FILENAME = "rudder_expected_reports.csv"


override def handle(agentType: AgentType): Boolean = agentType == COMMUNITY_AGENT || agentType == NOVA_AGENT

override def write(cfg: AgentNodeWritableConfiguration): Box[List[AgentSpecificFile]] = {
writeExpectedReportsCsv(cfg.paths, cfg.expectedReportsCsv, GENEREATED_CSV_FILENAME)
}


private[this] def writeExpectedReportsCsv(paths: NodePromisesPaths, csv: ExpectedReportsCsv, csvFilename: String): Box[List[AgentSpecificFile]] = {
val path = new File(paths.newFolder, csvFilename)
for {
_ <- tryo { FileUtils.writeStringToFile(path, csv.lines.mkString("\n"), Codec.UTF8.charSet) } ?~!
s"Can not write the expected reports CSV file at path '${path.getAbsolutePath}'"
} yield {
AgentSpecificFile(path.getAbsolutePath) :: Nil
}
}
}

/*
* This will go in the plugin, and will be contributed somehow at config time.
*/
object DscAgentSpecificGeneration extends AgentSpecificGeneration {

override def handle(agentType: AgentType): Boolean = agentType == DSC_AGENT

override def write(cfg: AgentNodeWritableConfiguration): Box[List[AgentSpecificFile]] = {
writeSystemVarJson(cfg.paths)
}

// just write an empty file for now
private[this] def writeSystemVarJson(paths: NodePromisesPaths) = {
val path = new File(paths.newFolder, "rudder.json")
for {
_ <- tryo { FileUtils.writeStringToFile(path, """{ "comment":"for now, an empty file" } \n""", Codec.UTF8.charSet) } ?~!
s"Can not write json parameter file at path '${path.getAbsolutePath}'"
} yield {
AgentSpecificFile(path.getAbsolutePath) :: Nil
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ class Cf3PromisesFileWriterServiceImpl(
) extends PolicyWriterService with Loggable {

val TAG_OF_RUDDER_ID = "@@RUDDER_ID@@"
val GENEREATED_CSV_FILENAME = "rudder_expected_reports.csv"

val newPostfix = ".new"
val backupPostfix = ".bkp"
Expand Down Expand Up @@ -251,30 +250,47 @@ class Cf3PromisesFileWriterServiceImpl(
}) match {
case s if s.charAt(0) == 'x' => (Runtime.getRuntime.availableProcessors * s.substring(1).toDouble).ceil.toInt
case other => other.toInt
}})
}
})
implicit val scheduler = Scheduler.io(executionModel = ExecutionModel.AlwaysAsyncExecution)

for {
configAndPaths <- calculatePathsForNodeConfigurations(interestingNodeConfigs, rootNodeId, allNodeConfigs, newPostfix, backupPostfix)
pathsInfo = configAndPaths.map { _.paths }
templates <- readTemplateFromFileSystem(techniqueIds)

//////////
// nothing agent specific before that
//////////


preparedPromises <- parrallelSequence(configAndPaths) { case agentNodeConfig =>
val nodeConfigId = versions(agentNodeConfig.config.nodeInfo.id)
prepareTemplate.prepareTemplateForAgentNodeConfiguration(agentNodeConfig, nodeConfigId, rootNodeId, templates, allNodeConfigs, TAG_OF_RUDDER_ID, globalPolicyMode)
}
val nodeConfigId = versions(agentNodeConfig.config.nodeInfo.id)
prepareTemplate.prepareTemplateForAgentNodeConfiguration(agentNodeConfig, nodeConfigId, rootNodeId, templates, allNodeConfigs, TAG_OF_RUDDER_ID, globalPolicyMode)
}
promiseWritten <- parrallelSequence(preparedPromises) { prepared =>
for {
_ <- writePromises(prepared.paths, prepared.preparedTechniques)
_ <- writeExpectedReportsCsv(prepared.paths, prepared.expectedReportsCsv, GENEREATED_CSV_FILENAME)
_ <- WriteAllAgentSpecificFiles.write(prepared)
} yield {
"OK"
}
}
propertiesWritten <- parrallelSequence(configAndPaths) { case agentNodeConfig =>

//////////
// nothing agent specific after that
//////////

propertiesWritten <- parrallelSequence(configAndPaths) { case agentNodeConfig =>
writeNodePropertiesFile(agentNodeConfig) ?~!
s"An error occured while writing property file for Node ${agentNodeConfig.config.nodeInfo.hostname} (id: ${agentNodeConfig.config.nodeInfo.id.value}"
}

licensesCopied <- copyLicenses(configAndPaths, allLicenses)

/// perhaps that should be a post-hook somehow ?
// and perhaps we should have an AgentSpecific global pre/post write

nodePreMvHooks <- RunHooks.getHooks(HOOKS_D + "/policy-generation-node-ready", HOOKS_IGNORE_SUFFIXES)
preMvHooks <- parrallelSequence(configAndPaths) { agentNodeConfig =>
val timeHooks = System.currentTimeMillis
Expand Down Expand Up @@ -399,18 +415,8 @@ class Cf3PromisesFileWriterServiceImpl(
res
}

private[this] def writeExpectedReportsCsv(paths: NodePromisesPaths, csv: ExpectedReportsCsv, csvFilename: String): Box[String] = {
val path = new File(paths.newFolder, csvFilename)
for {
_ <- tryo { FileUtils.writeStringToFile(path, csv.lines.mkString("\n"), Codec.UTF8.charSet) } ?~!
s"Can not write the expected reports CSV file at path '${path.getAbsolutePath}'"
} yield {
path.getAbsolutePath
}
}

private[this] def writePromises(
paths : NodePromisesPaths
paths : NodePromisesPaths
, preparedTechniques: Seq[PreparedTechnique]
) : Box[NodePromisesPaths] = {
// write the promises of the current machine and set correct permission
Expand All @@ -432,6 +438,7 @@ class Cf3PromisesFileWriterServiceImpl(
}
}


/**
* For agent needing it, copy licences to the correct path
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@

package com.normation.rudder.services.policies.write

import scala.io.Codec

import com.normation.cfclerk.domain.PARAMETER_VARIABLE
import com.normation.cfclerk.domain.SectionVariableSpec
import com.normation.cfclerk.domain.SystemVariable
Expand All @@ -55,16 +53,15 @@ import com.normation.cfclerk.services.TechniqueRepository
import com.normation.inventory.domain.COMMUNITY_AGENT
import com.normation.inventory.domain.NOVA_AGENT
import com.normation.inventory.domain.NodeId
import com.normation.rudder.domain.policies.GlobalPolicyMode
import com.normation.rudder.domain.policies.PolicyMode
import com.normation.rudder.domain.reports.NodeConfigId
import com.normation.rudder.services.policies.nodeconfig.NodeConfiguration
import com.normation.templates.STVariable
import com.normation.utils.Control._

import org.joda.time.DateTime

import net.liftweb.common._
import com.normation.rudder.domain.policies.GlobalPolicyMode
import com.normation.rudder.domain.policies.PolicyMode
import org.joda.time.DateTime
import scala.io.Codec

trait PrepareTemplateVariables {

Expand Down Expand Up @@ -133,10 +130,17 @@ class PrepareTemplateVariablesImpl(
agentNodeConfig.config.nodeInfo.id, container, allSystemVars, templates, generationTimestamp
)

logger.trace(s"${agentNodeConfig.config.nodeInfo.id.value}: creating lines for expected reports CSV files")
val csv = ExpectedReportsCsv(prepareReportingDataForMetaTechnique(container, rudderIdCsvTag))

AgentNodeWritableConfiguration(agentNodeConfig.paths, preparedTemplate.values.toSeq, csv)
// we only need to generate expected_reports.csv for CFEngine-like agent
val csv = ExpectedReportsCsv(agentNodeConfig.agentType match {
case COMMUNITY_AGENT | NOVA_AGENT =>
logger.trace(s"${agentNodeConfig.config.nodeInfo.id.value}: creating lines for expected reports CSV files")
prepareReportingDataForMetaTechnique(container, rudderIdCsvTag)
case _ => // DSC_AGENT or other
logger.trace(s"${agentNodeConfig.config.nodeInfo.id.value}: not creating lines for expected reports CSV files - agent type '${agentNodeConfig.agentType.fullname}' does not need them")
Seq()
})

AgentNodeWritableConfiguration(agentNodeConfig.agentType, agentNodeConfig.paths, preparedTemplate.values.toSeq, csv)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ case class AgentNodeConfiguration(
* - the expected reports csv file content
*/
final case class AgentNodeWritableConfiguration(
paths : NodePromisesPaths
agentType : AgentType
, paths : NodePromisesPaths
, preparedTechniques: Seq[PreparedTechnique]
, expectedReportsCsv: ExpectedReportsCsv
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<!--
Copyright 2017 Normation SAS
This program 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, Version 3.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<xml>
<name>DSC Specific system techniques</name>
<description>
This category contains internal Techniques (system) for
DSC agent.
These Techniques should not be used directly.
</description>
<system>true</system>
</xml>
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<!--
Copyright 2017 Normation SAS
This program 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, Version 3.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->

<TECHNIQUE name="DSC Agant">
<DESCRIPTION>System technique for the DSC Agent</DESCRIPTION>
<SYSTEM>true</SYSTEM>

<TMLS>
<!-- There should be not TML in DSC agent -->
<!-- <TML name="blabla"/> -->
</TMLS>

<FILES>
<FILE name="rudder.ps1">
<OUTPATH>rudder.ps1</OUTPATH>
<INCLUDED>false</INCLUDED>
</FILE>
<FILE name="some-resource.conf" />
</FILES>

<BUNDLES>
<!-- <NAME>main</NAME> -->
</BUNDLES>

<SYSTEMVARS>
<!-- Perhaps we will have specific system vars? -->
<!-- <NAME>SOME_DSC_SPECIFIC_SYSTEM_VAR</NAME> -->
</SYSTEMVARS>

<SECTIONS>
<!-- This is just some examples -->
<SECTION name="Update" component="true" />
<SECTION name="ncf Initialization" component="true" />
<SECTION name="Security parameters" component="true" />
<SECTION name="Log system for reports" component="true" />
</SECTIONS>

</TECHNIQUE>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string] $action = "run",
[string] $class = $null
)

Write-Error "Not an actual agent"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Blabla bla bla some conf.

Done.
Loading

0 comments on commit 909bae9

Please sign in to comment.