I am getting an error when trying to execute my puppet module:
Error 400 on SERVER: certificatefqdn is not a hash or array when accessing it with certificatefile
This is what my hiera file looks like:
testmodule::install::certificates:
test1.domain.com:
certificatefile: 'certificate1.crt'
certificatepass: 'testpass1'
test2.domain.com:
certificatefile: 'certificate2.crt'
certificatepass: 'testpass2'
test3.domain.com:
certificatefile: 'certificate3.crt'
certificatepass: 'testpass3'
The init.pp in my module looks like this:
class testmodule (
$certificates = hiera('testmodule::install::certificates'),
)
{
$domains = [
test1.domain.com',
test2.domain.com',
test3.domain.com',
[
testmodule::install { $domains:
certificates => $certificates,
}
}
The install.pp in my module looks like this:
define testmodule::install ($certificates)
{
$domain = $name
$certificatefqdn = $certificates["$domain"]
$certificatefile = $certificatefqdn['certificatefile']
$certificatepass = $certificatefqdn['certificatepass']
notify{"This is the certificate file: $certificatefile" :}
}
I'm expecting to see an output like this for each of the elements in the domain array:
Notice: This is the certificate file: certificate2.crt
Notice: /Stage[main]/Testmodule/Testmodule::Install[certificate2.crt]/Notify[This is the certificate file: certificate2.crt]/message: defined 'message' as 'This is the certificate file: certificate2.crt'
Instead I see this:
Notice: This is the certificate file: test2.domain.com['certificatefile']
Notice: /Stage[main]/Testmodule/Testmodule::Install[test2.domain.com]/Notify[This is the certificate file: test2.domain.com['certificatefile']]/message: defined 'message' as 'This is the certificate file: test2.domain.com['certificatefile']'
How can I correctly access the keys in the nested hash in hiera using the elements in domains as the initial key?
The code appears to be correct already.
I have set this up according to your question:
1/
# manifests/init.pp
class test (
$certificates = hiera('test::install::certificates'),
) {
$domains = [
'test1.domain.com',
'test2.domain.com',
'test3.domain.com',
]
test::install { $domains:
certificates => $certificates,
}
}
2/
# manifests/install.pp
define test::install ($certificates) {
$domain = $name
$certificatefqdn = $certificates["$domain"]
$certificatefile = $certificatefqdn['certificatefile']
$certificatepass = $certificatefqdn['certificatepass']
notify{"This is the certificate file: $certificatefile" :}
}
3/
# spec/fixtures/hiera/data/common.yaml
---
test::install::certificates:
test1.domain.com:
certificatefile: 'certificate1.crt'
certificatepass: 'testpass1'
test2.domain.com:
certificatefile: 'certificate2.crt'
certificatepass: 'testpass2'
test3.domain.com:
certificatefile: 'certificate3.crt'
certificatepass: 'testpass3'
4/
# spec/fixtures/hiera/hiera.yaml
---
version: 5
defaults:
datadir: data
data_hash: yaml_data
hierarchy:
- name: "All levels"
paths:
- common.yaml
Compile and apply:
$ bundle exec puppet apply --modulepath spec/fixtures/modules --hiera_config spec/fixtures/hiera/hiera.yaml -e 'include test'
Warning: The function 'hiera' is deprecated in favor of using 'lookup'. See https://docs.puppet.com/puppet/5.3/reference/deprecated_language.html
(file & line not available)
Notice: Compiled catalog for alexs-macbook-pro.local in environment production in 0.14 seconds
Notice: This is the certificate file: certificate1.crt
Notice: /Stage[main]/Test/Test::Install[test1.domain.com]/Notify[This is the certificate file: certificate1.crt]/message: defined 'message' as 'This is the certificate file: certificate1.crt'
Notice: This is the certificate file: certificate2.crt
Notice: /Stage[main]/Test/Test::Install[test2.domain.com]/Notify[This is the certificate file: certificate2.crt]/message: defined 'message' as 'This is the certificate file: certificate2.crt'
Notice: This is the certificate file: certificate3.crt
Notice: /Stage[main]/Test/Test::Install[test3.domain.com]/Notify[This is the certificate file: certificate3.crt]/message: defined 'message' as 'This is the certificate file: certificate3.crt'
Notice: Applied catalog in 0.04 seconds
So I can't reproduce this.
Related
I am trying to generate a file by template rendering to pass to the user data of the ec2 instance. I am using the third party terraform provider to generate an ignition file from the YAML.
data "ct_config" "worker" {
content = data.template_file.file.rendered
strict = true
pretty_print = true
}
data "template_file" "file" {
...
...
template = file("${path.module}/example.yml")
vars = {
script = file("${path.module}/script.sh")
}
}
example.yml
storage:
files:
- path: "/opt/bin/script"
mode: 0755
contents:
inline: |
${script}
Error:
Error: Error unmarshaling yaml: yaml: line 187: could not find expected ':'
on ../../modules/launch_template/launch_template.tf line 22, in data "ct_config" "worker":
22: data "ct_config" "worker" {
If I change ${script} to sample data then it works. Also, No matter what I put in the script.sh I am getting the same error.
You want this outcome (pseudocode):
storage:
files:
- path: "/opt/bin/script"
mode: 0755
contents:
inline: |
{{content of script file}}
In your current implementation, all lines after the first loaded from script.sh will not be indented and will not be interpreted as desired (the entire script.sh content) by a YAML decoder.
Using indent you can correct the indentation and using the newer templatefile functuin you can use a slightly cleaner setup for the template:
data "ct_config" "worker" {
content = local.ct_config_content
strict = true
pretty_print = true
}
locals {
ct_config_content = templatefile("${path.module}/example.yml", {
script = indent(10, file("${path.module}/script.sh"))
})
}
For clarity, here is the example.yml template file (from the original question) to use with the code above:
storage:
files:
- path: "/opt/bin/script"
mode: 0755
contents:
inline: |
${script}
I had this exact issue with ct_config, and figured it out today. You need to base64encode your script to ensure it's written correctly without newlines - without that, newlines in your script will make it to CT, which attempts to build an Ignition file, which cannot have newlines, causing the error you ran into originally.
Once encoded, you then just need to tell CT to !!binary the file to ensure Ignition correctly base64 decodes it on deploy:
data "template_file" "file" {
...
...
template = file("${path.module}/example.yml")
vars = {
script = base64encode(file("${path.module}/script.sh"))
}
}
storage:
files:
- path: "/opt/bin/script"
mode: 0755
contents:
inline: !!binary |
${script}
I am attempting to define my user accounts as Hashes in Hiera, like this:
---
accounts::user:
jack:
ensure: present
bashrc_content: file('accounts/shell/bashrc')
bash_profile_content: file('accounts/shell/bash_profile')
It works fine if I define them in my *.pp files.
Please, find more details about hiera.yaml, manifest and users.yamal on Gist
Why doesn't this work?
P.S. This question continues to,
No, what you are trying to do is not possible.
I have a few options for you. In Hiera, you could have all of the data other than the call to the file() function:
---
accounts::user:
jack:
locked: false
comment: Jack Doe
ensure: present
groups:
- admins
- sudo
shell: '/bin/bash'
home_mode: '0700'
purge_sshkeys: false
managehome: true
managevim: false
sshkeys:
- ssh-rsa AAAA
password: '70'
And then in your manifest:
$defaults = {
'bashrc_content' => file('accounts/shell/bashrc'),
'bash_profile_content' => file('accounts/shell/bash_profile'),
}
$user_data = lookup('accounts::user', Hash[String,Hash], 'hash', {})
$user_data.each |$user,$props| {
accounts::user { $user: * => $props + $defaults }
}
Another option is to simply include your file content in the YAML data, i.e.
---
accounts::user:
jack:
locked: false
comment: Jack Doe
ensure: present
groups:
- admins
- sudo
shell: '/bin/bash'
home_mode: '0700'
purge_sshkeys: false
managehome: true
managevim: false
bashrc_content: |
# If not running interactively, don't do anything
[ -z "$PS1" ] && return
if [ -f /etc/bashrc ]; then
. /etc/bashrc # --> Read /etc/bashrc, if present.
fi
...
bash_profile_content: ...
sshkeys:
- ssh-rsa AAAA
password: '70'
Then you won't need the file function or the files at all.
For more info:
On what you can interpolate in Hiera data.
The splat operator (*) and a useful blog on how to use it.
On multiline-strings in YAML.
I want to create SSL certificate and try to secure this operation.
I am using Puppet 5.5.2 and gem hiera-eyaml.
Created simple manifest
cat /etc/puppetlabs/code/environments/production/manifests/site.pp
package { 'tree':
ensure => installed,
}
package { 'httpd':
ensure => installed,
}
$filecrt = lookup('files')
create_resources( 'file', $filecrt )
Hiera config
---
version: 5
defaults:
# The default value for "datadir" is "data" under the same directory as the hiera.yaml
# file (this file)
# When specifying a datadir, make sure the directory exists.
# See https://puppet.com/docs/puppet/latest/environments_about.html for further details on environments.
datadir: data
data_hash: yaml_data
hierarchy:
- name: "Secret data: per-node, per-datacenter, common"
lookup_key: eyaml_lookup_key # eyaml backend
paths:
- "nodes/%{facts.fqdn}.eyaml"
- "nodes/%{trusted.certname}.eyaml" # Include explicit file extension
- "location/%{facts.whereami}.eyaml"
- "common.eyaml"
options:
pkcs7_private_key: /etc/puppetlabs/puppet/eyaml/keys/private_key.pkcs7.pem
pkcs7_public_key: /etc/puppetlabs/puppet/eyaml/keys/public_key.pkcs7.pem
- name: "YAML hierarchy levels"
paths:
- "common.yaml"
- "nodes/%{facts.fqdn}.yaml"
- "nodes/%{::trusted.certname}.yaml"
And common.yaml
---
files:
'/etc/httpd/conf/server.crt':
ensure: present
mode: '0600'
owner: 'root'
group: 'root'
content: 'ENC[PKCS7,{LOT_OF_STRING_SKIPPED}+uaCmcHgDAzsPD51soM+AIkIlv0ANpUXzBpwM3tqQ3ysFtz81S0xuVbKvslK]'
But have en error while applying manifest
Error: Evaluation Error: Error while evaluating a Function Call, create_resources(): second argument must be a hash (file: /etc/puppetlabs/code/environments/production/manifests/site.pp, line: 12, column: 1) on node test1.com
I really dont know what to do )
The problem appears to be that the indentation in common.yaml isn't right - currently, file will be null rather than a hash, which explains the error message. Also, the file should be called common.eyaml, otherwise the ENC string won't be decrypted. Try
---
files:
'/etc/httpd/conf/server.crt':
ensure: present
mode: '0600'
owner: 'root'
group: 'root'
content: 'ENC[PKCS7{LOTS_OF_STRING_SKIPPED}UXzBpwM3tqQ3ysFtz81S0xuVbKvslK]'
There is an online YAML parser at http://yaml-online-parser.appspot.com/ if you want to see the difference the indentation makes.
Found another solution.
Its was a problem with lookup and hashes. When I have multiply lines in hiera hash, I must specify them https://docs.puppet.com/puppet/4.5/function.html#lookup
So i decided use only 'content' variable to lookup
cat site.pp
$filecrt = lookup('files')
file { 'server.crt':
ensure => present,
path => '/etc/httpd/conf/server.crt',
content => $filecrt,
owner => 'root',
group => 'root',
mode => '0600',
}
and Hiera
---
files:'ENC[PKCS7{LOT_OF_STRING_SKIPPED}+uaCmcHgDAzsPD51soM+AIkIlv0ANpUXzBpwM3tqQ3ysFtz81S0xuVbKvslK]'
I have created a proxy_match.yaml file as a hiera source file in
default hiera datalocation.
The proxy_match.yaml is added in hiera hierarchy
Looking up hiera data in profile
Where and what am I missing, I am not able to receive the hiera data
value and thus the error appears mentioned bellow.
Where,
proxy_match is the new environment created
hierafile 1
/etc/puppetlabs/code/environments/proxy_match/hiera.yaml
version: 5
defaults:
# The default value for "datadir" is "data" under the same directory as the hiera.yaml
# file (this file)
# When specifying a datadir, make sure the directory exists.
# See https://docs.puppet.com/puppet/latest/environments.html for further details on environments.
# datadir: data
# data_hash: yaml_data
hierarchy:
- name: "environment specific yaml"
path: "proxy_match.yaml"
- name: "Per-node data (yaml version)"
path: "nodes/%{::trusted.certname}.yaml"
- name: "Other YAML hierarchy levels"
paths:
- "common.yaml"
proxy_match.yaml hiera data source file
This is the yaml hiera source named as proxy_match.yaml as in herarchy
/etc/puppetlabs/code/environments/proxy_match/data/proxy-match.yaml
---
profiles::apache::servername: "taraserver.com"
profiles::apache::port: "80"
profiles::apache::docroot: "/var/www/tarahost"
hiera lookup in profile
$servername = hiera('profiles::apache::servername',{})
$port = hiera('profiles::apache::port',{})
$docroot = hiera('profiles::apache::docroot',{})
class profile::apache{
#configure apache
include apache
apache::vhost{$servername:
port => $port,
docroot => $docroot,
}
}
#ERROR:
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Loading facts
Error: Could not retrieve catalog from remote server: Error 500 on SERVER: {"message":"Server Error: Evaluation Error: Error while evaluating a Resource Statement, Apache::Vhost[7fba80ae621c.domain.name]: parameter 'docroot' expects a value of type Boolean or String, got Undef at /etc/puppetlabs/code/environments/proxy_match/modules/profile/manifests/apache.pp:29 on node 94707b03ff05.domain.name","issue_kind":"RUNTIME_ERROR"}
Warning: Not using cache on failed catalog
Error: Could not retrieve catalog; skipping run
You are defining the variables outside the class definition. When Puppet loads that class, those lines you have before the class are ignored.
What you should have in your profile class is:
class profiles::apache (
String $servername,
Integer $port,
String $docroot,
) {
include apache
apache::vhost { $servername:
port => $port,
docroot => $docroot,
}
}
Note that I used the automatic parameter lookup feature to set your variables, instead of explicit calls to the hiera function.
is there a way to use a variable defined in some manifest with hiera?
This is how I tried it:
manifest.pp
if $::ipaddress_bond0 {
$primary_interface = 'bond0'
notify{"$primary_interface":}
}
else {
$primary_interface = 'eth0'
notify{"$primary_interface":}
}
hiera.yaml
some_config:
server:
foo:
bar: "%{::primary_interface}"
Yes it is possible. Look at the example:
test.pp
class nodes::test
{
$value1 = 'abc'
$value2 = hiera('test::value2')
$value3 = hiera('test::value3')
notify{ " v1 ${value1}": }
notify{ " v2 ${value2}": }
notify{ " v3 ${value3}": }
}
include nodes::test
test.yaml
test::value2: "%{value1}"
test::value3: "%{value4}"
run test:
puppet apply test.pp
Notice: v1 abc
Notice: v2 abc
Notice: v3
Keep in mind that using puppet variables in hiera is a really bad practice.