0

我想在定义的类型中创建文件。我已经尝试了几种方法,但无法解决问题。让我解释一下我的情况。

我正在使用 temapltes 创建一些文件,我可以完美地完成该操作。我正在使用以下 ruby​​ 函数来收集文件名、位置类型的数据

require 'rexml/document'
include REXML
module Puppet::Parser::Functions
newfunction(:getConfigFileDetails, :type => :rvalue ) do |args|
    fileDetails= []
    doc = REXML::Document.new args[0]
    doc.elements.each("node/congfigurations/config") {
     |config|
            fileName= config.elements["@fileName"].value
            fileLocation= config.elements["@location"].value
            fileDetails << {'filename' => fileName, 'filelocation'=> fileLocation}
    }
    return fileDetails
  end
end

我在我的木偶类中使用了这个函数,它对我来说很好用

define fill_templates() {
  $fileName = $name["filename"]
  $fileLocation = $name['filelocation']
  file { "${fileLocation}/${fileName}/":
    ensure  => present,
    owner   => 'root',
    group   => 'root',
    mode    => '0777',
    content => template("config/${fileName}.erb"),
    require => Exec["unzip_pack"],
 }

}

$configFileDetails = getConfigFileDetails($allConfigurations['configurations'])
fill_templates { $configFileDetails: }

然后我尝试使用我自己的内容创建文件,而不是从模板中获取数据。以下是我的红宝石功能

 require 'rexml/document'
 include REXML
 module Puppet::Parser::Functions
    newfunction(:getCreateFileDetails, :type => :rvalue ) do |args|
            fileDetails= []
            doc = REXML::Document.new args[0]
            doc.elements.each("node/create/file") {
            |filedata|
                    fileName= filedata.elements["filename"].text
                    fileLocation= filedata.elements["location"].text
                    fileContent= filedata.elements["content"].text
                    fileDetails << {'filename' => fileName, 'filelocation'=> fileLocation, 'filecontent'=> fileContent }
            }
            return fileDetails
    end
end

我在我的木偶类中使用它如下

define create_files() {
$fileName = $name["filename"]
$fileLocation = $name['filelocation']
$fileContent = $name['filecontent']
file { "${fileLocation}/${fileName}/":
    ensure  => present,
    owner   => 'root',
    group   => 'root',
    content => "$fileContent",
   }
  }
   $createFileDetails = getCreateFileDetails($allConfigurations['configurations'])
   create_files { $createFileDetails: }

但它总是给我错误

Could not retrieve catalog from remote server: Could not intern from pson: Could not convert from pson: Could not find relationship target

我无法意识到这个问题的原因。前一个模板工作而后一个模板不工作的原因是什么。

感谢您对此的关注

4

1 回答 1

2

我什至不会尝试了解您的第一种方法是如何起作用的。它违反了 Puppet 清单语义的一些基本规则。

基本上,如果你想导入一个数据结构(从任何地方,真的)并从中产生资源(通过定义的或本机类型),它应该被构造为一个哈希:

{
  'resource-name1' => {
    'attribute-name1' => 'value',
    'attribute-name2' => 'value',
    ...
  },
  'resource-name2' => {
    ...
  }
}, ...

建立一个像

[
  { attribute1 => value, attribute2 => value, ... },
  { ... },
]

并且将每个作为资源的名称传递是无效的。

要解决您的问题,请让自定义函数返回适当的哈希值。(重命名以避免驼峰式 - 不是 Puppet 的习惯。)

require 'rexml/document'
include REXML
module Puppet::Parser::Functions
  newfunction(:get_config_file_details, :type => :rvalue ) do |args|
    result = {}
    doc = REXML::Document.new args[0]
    doc.elements.each("node/create/file") { |filedata|
      name     = filedata.elements["filename"].text
      location = filedata.elements["location"].text
      conent   = filedata.elements["content"].text
      result[name] = {
        'fileLocation' => location,
        'fileContent'  => content,
      }
    }
    result
  end
end

您定义的类型需要接受实际参数。(除此之外:create_files对于类型来说这是一个非常糟糕的名称 - 类型名称应该是单数的,并且描述每个资源实例所代表的内容。)

define my_config_file($fileName=$name, $fileLocation, $fileContent) {
    file { "${fileLocation}/${fileName}/":
    ...
}

最后,要从散列创建适当的实例,请使用该create_resources函数。

$my_config_file_data = get_config_file_details($xml)
create_resources('my_config_files', $my_config_file_data)

最后的建议:如果可能的话,以适当的 YAML 或 JSON 格式而不是 XML 序列化您的数据。您可以使这些对 Hiera 可用并通过该hiera()函数直接加载它们 - 无需自定义 Ruby 代码。

于 2014-08-18T11:23:13.063 回答