diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/Cf3PromisesFileWriterService.scala b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/Cf3PromisesFileWriterService.scala index 27e3699095e..35453b560aa 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/Cf3PromisesFileWriterService.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/Cf3PromisesFileWriterService.scala @@ -290,6 +290,7 @@ class Cf3PromisesFileWriterServiceImpl( configAndPaths <- calculatePathsForNodeConfigurations(interestingNodeConfigs, rootNodeId, allNodeConfigs, newPostfix, backupPostfix) pathsInfo = configAndPaths.map { _.paths } templates <- readTemplateFromFileSystem(techniqueIds) + resources <- readResourcesFromFileSystem(techniqueIds) readTemplateTime2 = DateTime.now.getMillis readTemplateDur = readTemplateTime2 - readTemplateTime1 @@ -307,7 +308,7 @@ class Cf3PromisesFileWriterServiceImpl( promiseWritten <- parrallelSequence(preparedPromises) { prepared => (for { - _ <- writePromises(prepared.paths, prepared.preparedTechniques) + _ <- writePromises(prepared.paths, prepared.preparedTechniques, resources) _ <- writeExpectedReportsCsv(prepared.paths, prepared.expectedReportsCsv, GENEREATED_CSV_FILENAME) _ <- writeSystemVarJson(prepared.paths, prepared.systemVariables) } yield { @@ -491,6 +492,45 @@ class Cf3PromisesFileWriterServiceImpl( res } + /* + * We are returning a map where keys are (TechniqueResourceId, AgentType) because + * for a given resource IDs, you can have different out path for different agent. + */ + private[this] def readResourcesFromFileSystem( + techniqueIds: Set[TechniqueId] + )(implicit scheduler: Scheduler, semaphore: TaskSemaphore): Box[Map[TechniqueResourceId, TechniqueResourceCopyInfo]] = { + + val staticResourceToRead = for { + technique <- techniqueRepository.getByIds(techniqueIds.toSeq) + staticResource <- technique.files.map(t => (t.id, t.outPath)) + } yield { + staticResource + } + + val now = System.currentTimeMillis() + + val res = (parrallelSequence(staticResourceToRead) { case (templateId, templateOutPath) => + for { + copyInfo <- techniqueRepository.getFileContent(templateId) { optInputStream => + optInputStream match { + case None => + Failure(s"Error when trying to open template '${templateId.toString}'. Check that the file exists with a ${TechniqueTemplate.templateExtension} extension and is correctly commited in Git, or that the metadata for the technique are corrects.") + case Some(inputStream) => + logger.trace(s"Loading template: ${templateId}") + //string template does not allows "." in path name, so we are force to use a templateGroup by polity template (versions have . in them) + val content = IOUtils.toString(inputStream, Codec.UTF8.charSet) + Full(TechniqueResourceCopyInfo(templateId, templateOutPath, content)) + } + } + } yield { + (copyInfo.id, copyInfo) + } + }).map( _.toMap) + + logger.debug(s"${staticResourceToRead.size} promises resources read in ${System.currentTimeMillis-now} ms") + res + } + private[this] def writeExpectedReportsCsv(paths: NodePromisesPaths, csv: ExpectedReportsCsv, csvFilename: String): Box[String] = { val path = new File(paths.newFolder, csvFilename) for { @@ -545,8 +585,9 @@ class Cf3PromisesFileWriterServiceImpl( private[this] def writePromises( - paths : NodePromisesPaths + paths : NodePromisesPaths , preparedTechniques: Seq[PreparedTechnique] + , resources : Map[TechniqueResourceId, TechniqueResourceCopyInfo] ) : Box[NodePromisesPaths] = { // write the promises of the current machine and set correct permission for { @@ -556,7 +597,7 @@ class Cf3PromisesFileWriterServiceImpl( writePromisesFiles(template, preparedTechnique.environmentVariables , paths.newFolder) } files <- sequence(preparedTechnique.filesToCopy.toSeq) { file => - copyResourceFile(file, paths.newFolder) + copyResourceFile(file, paths.newFolder, resources) } } yield { "OK" @@ -657,21 +698,22 @@ class Cf3PromisesFileWriterServiceImpl( /** * Copy a resource file from a technique to the node promises directory */ - private[this] def copyResourceFile(file: TechniqueFile, rulePath: String): Box[String] = { + private[this] def copyResourceFile( + file: TechniqueFile + , rulePath: String + , resources : Map[TechniqueResourceId, TechniqueResourceCopyInfo] + ): Box[String] = { val destination = new File(rulePath+"/"+file.outPath) - techniqueRepository.getFileContent(file.id) { optStream => - optStream match { - case None => Failure(s"Can not open the technique resource file ${file.id} for reading") - case Some(s) => - try { - FileUtils.copyInputStreamToFile(s, destination) - Full(destination.getAbsolutePath) - } catch { - case ex: Exception => Failure(s"Error when copying technique resoure file '${file.id}' to '${destination.getAbsolutePath}')", Full(ex), Empty) - } - } - + resources.get(file.id) match { + case None => Failure(s"Can not open the technique resource file ${file.id} for reading") + case Some(s) => + try { + FileUtils.writeStringToFile(destination, s.content, Codec.UTF8.charSet) + Full(destination.getAbsolutePath) + } catch { + case ex: Exception => Failure(s"Error when copying technique resoure file '${file.id}' to '${destination.getAbsolutePath}')", Full(ex), Empty) + } } } diff --git a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PromiseWriteDataStructures.scala b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PromiseWriteDataStructures.scala index 64a141c31d5..365aeb6d613 100644 --- a/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PromiseWriteDataStructures.scala +++ b/rudder-core/src/main/scala/com/normation/rudder/services/policies/write/PromiseWriteDataStructures.scala @@ -120,5 +120,14 @@ case class TechniqueTemplateCopyInfo( , destination: String , content : String //template content as a file ) extends HashcodeCaching { - override def toString() = s"Promise template ${id.name}; destination ${destination}" + override def toString() = s"Technique template ${id.name}; destination ${destination}" +} + + +case class TechniqueResourceCopyInfo( + id : TechniqueResourceId + , destination: String + , content : String //template resource as a file +) extends HashcodeCaching { + override def toString() = s"Technique resource ${id.name}; destination ${destination}" }