Cannot create files inside defined type

牧云@^-^@ 提交于 2019-12-11 23:11:53

问题


I want to create files inside a defined type. I have tried it several ways but couldn't solve the issue. Let me explain you my case.

I am creating some files using temapltes and I could do that operation perfectly. I am using below ruby function to gather filename, location kind of data

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

And I use this function inside my puppet class and it works fine for me

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: }

Then I tried to create files with my own content in them not get data from templates. Following is my ruby function

 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

And I use it inside my puppet class as follows

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: }

But it always gives me error

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

I cannot realize the cause for this issue. What is the reason the previous template one working and the later one is not working.

Thank you for your light on this


回答1:


I won't even try to understand how your first approach ever worked. It defies some basic rules of Puppet manifest semantics.

Basically, if you want to import a data structure (from anywhere, really) and spawn resources from that (through a defined or a native type), it should be structured as a hash:

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

Building an array like

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

And passing each as the name for a resource is not valid by a long shot.

To fix your issue, make the custom function return an appropriate hash. (Renaming to avoid camel case - not a Puppet custom.)

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

Your defined types needs to accept actual parameters. (Aside: create_files is a very bad name for a type - type names should be singular, and descriptive of what each resource instance represents.)

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

Finally, to create the appropriate instances from the hash, use the create_resources function.

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

Final advice: If this is at all possible, serialize your data in an appropriate YAML or JSON format instead of XML. You can make those available to Hiera and load them directly through the hiera() function - no custom Ruby code needed.



来源:https://stackoverflow.com/questions/25351350/cannot-create-files-inside-defined-type

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!