I have a puppet manifest that contains this phrase (my question is about the production block at the end), used to set up mysql configuration files:
class web_mysql_server {
include web_mysql::packages
include web_mysql::mysql_server
}
class web_mysql::packages {
Package { ensure => installed }
package { 'libmysqlclient-dev': }
}
class web_mysql::mysql_server {
# Qualified keys (dot notation: web_mysql_server.mysql_database) isn't available
# until hiera 2.0.
$mysql_config = hiera('web_mysql_server')
# https://forge.puppetlabs.com/puppetlabs/mysql
class { '::mysql::server':
root_password => '...',
remove_default_accounts => true,
override_options => {
# The data in this block gets written to /etc/mysql/my.cnf.
'mysqld' => {
max_connections => '1024', # No good reason but parroting others.
key_buffer_size => '512M', # No good reason but parroting others.
},
'production' => {
adaptor => 'mysql2',
database => $mysql_config['mysql_database'],
user => $mysql_config['mysql_username'],
password => $mysql_config['mysql_password'],
host => '0.0.0.0',
encoding => 'UTF8',
},
But sometimes I'd maybe like the database to be a staging database, and so it's a bit confusing to call it production. No problem, I've recently learned about hiera, it's my hammer for all nails today:
$mysql_config['mysql_name'] => {
adaptor => 'mysql2',
database => $mysql_config['mysql_database'],
user => $mysql_config['mysql_username'],
password => $mysql_config['mysql_password'],
host => '0.0.0.0',
encoding => 'UTF8',
},
No, that doesn't work, though the error ("syntax error at line (...with '=>'...), expected '}'") isn't terribly revealing.
("Key" might be the wrong word. Please correct me. I'm a bit new to puppet. And that itself may be why I've not been able to answer this question by googling and reading.)
Thanks for any pointers.
Update: I see now that the mysql module provides an option to add section to the config file out of the box. Here is how it should be used according to the documentation:
$override_options = {
$mysql_config['mysql_name'] => {
adaptor => 'mysql2',
database => $mysql_config['mysql_database']
# ...
}
}
class { '::mysql::server':
root_password => 'strongpassword',
remove_default_accounts => true,
override_options => $override_options,
}
Or you can save some code if you put the mysql_name value under a different hiera key:
$override_options = {
hiera('mysql_name') => hiera('web_mysql_server')
}
Original answer:
If your actual intention is just to create a configuration file, the best way is using templates in erb syntax.
Here is an example. First, you put a my.cnf.erb file to the templates directory of your module (e.g. modules/web_mysql/templates):
[<%= #mysql_config['mysql_name'] %>]
adaptor = mysql2
database = <%= #mysql_config['mysql_database'] %>
user = <%= #mysql_config['mysql_username'] %>
password = <%= #mysql_config['mysql_password'] %>
host = 0.0.0.0
encoding = UTF8
You can use this template in your web_mysql::mysql_server class to create the config file:
class web_mysql::mysql_server {
# ...
$mysql_config = hiera('web_mysql_server')
file { '/etc/mysql/my.cnf':
ensure => 'present',
content => template('web_mysql/my.cnf.erb'),
}
}
The way you're using web_mysql::mysql_server indicates that the class has a parameter called production. If that is the case you have to use that name when you use the class. Instead, why not just call the parameter mysql or client, since it seems to be the client configuration parameter?
Answer to original question:
Neither version of your manifest is valid Puppet. For example, putting this in my manifest:
'production' => {
adaptor => 'mysql2',
}
and running puppet apply --noop --modulepath modules manifests/host.pp results in:
Error: Could not parse for environment production: Syntax error at '=>' at [...]/host.pp:1:14 on node hostname
Did you mean to say something like this?
$database_configuration = {
adaptor => 'mysql2',
database => $mysql_config['mysql_database'],
user => $mysql_config['mysql_username'],
password => $mysql_config['mysql_password'],
host => '0.0.0.0',
encoding => 'UTF8',
}
Related
I have foreman query, which get puppet nodes from Foreman hostgroup.
I want use output from this query in my puppet manifest in nodes section.
My foreman query:
$query = foreman({foreman_user => 'admin',
foreman_pass => 'pass',
item => 'hosts',
search => 'hostgroup_fullname ~ web servers',
filter_result => ['certname'],
})
I want use "${_query}" variable in nodes class
Something like this:
node "${_query}" {
file { '/tmp/testdir':
ensure => 'directory',
}
file { '/tmp/testdir/testfile2':
ensure => present,
content => 'this is test file in directory',
owner => 'root',
group => 'root'
}
}
In normal Puppet manifest I must use this multiple nodes sintax:
node 'www1.example.com', 'www2.example.com', 'www3.example.com' {
file { '/tmp/testdir':
ensure => 'directory',
}
file { '/tmp/testdir/testfile2':
ensure => present,
content => 'this is test file in directory',
owner => 'root',
group => 'root'
}
}
When I execute my manifest with my foreman query I got this error:
Server Error: Could not parse for environment production: An interpolated expression is not allowed in a hostname of a node
I Understand the problem is in my foreman query variable.
How I must change my foreman query to use in myltiple nodes section in my manifest file?
Thanks in advance!
I want to inject some values from facter <prop> into a file content.
It works with $fqdn since facter fqdn returns string.
node default {
file {'/tmp/README.md':
ensure => file,
content => $fqdn, # $(facter fqdn)
owner => 'root',
}
}
However, it does not work with hash object (facter os):
node default {
file {'/tmp/README.md':
ensure => file,
content => $os, # $(facter os) !! DOES NOT WORK
owner => 'root',
}
}
And getting this error message when running puppet agent -t:
Error: Failed to apply catalog: Parameter content failed on
File[/tmp/README.md]: Munging failed for value
{"architecture"=>"x86_64", "family"=>"RedHat", "hardware"=>"x86_64",
"name"=>"CentOS", "release"=>{"full"=>"7.4.1708", "major"=>"7",
"minor"=>"4"}, "selinux"=>{"config_mode"=>"enforcing",
"config_policy"=>"targeted", "current_mode"=>"enforcing",
"enabled"=>true, "enforced"=>true, "policy_version"=>"28"}} in class
content: no implicit conversion of Hash into String (file:
/etc/puppetlabs/code/environments/production/manifests/site.pp, line:
2)
How to convert the hash to string inside the pp file?
If you have Puppet >= 4.5.0, it is now possible to natively convert various data types to strings in the manifests (i.e. in the pp files). The conversion functions are documented here.
This would do what you want:
file { '/tmp/README.md':
ensure => file,
content => String($os),
}
or better:
file { '/tmp/README.md':
ensure => file,
content => String($facts['os']),
}
On my Mac OS X, that leads to a file with:
{'name' => 'Darwin', 'family' => 'Darwin', 'release' => {'major' => '14', 'minor' => '5', 'full' => '14.5.0'}}
Have a look at all that documentation, because there are quite a lot of options that might be useful to you.
Of course, if you wanted the keys inside the $os fact,
file { '/tmp/README.md':
ensure => file,
content => $facts['os']['family'],
}
Now, if you don't have the latest Puppet, and you don't have the string conversion functions, the old way of doing this would be via templates and embedded Ruby (ERB), e.g.
$os_str = inline_template("<%= #os.to_s %>")
file { '/tmp/README.md':
ensure => file,
content => $os_str,
}
This actually leads to a slightly differently-formatted Hash since Ruby, not Puppet does the formatting:
{"name"=>"Darwin", "family"=>"Darwin", "release"=>{"major"=>"14", "minor"=>"5", "full"=>"14.5.0"}}
Running Puppet 3.8
I have two defines:
define desktop::vinstall () {
package { $title:
ensure => installed,
allow_virtual => true,
configfiles => keep,
}
}
and
define desktop::vinstallwseeds () {
package { $title:
ensure => installed,
allow_virtual => true,
configfiles => keep,
require => File["/var/cache/debconf/pkg-${title}.seeds"],
responsefile => "/var/cache/debconf/pkg-${title}.seeds",
}
file { "/var/cache/debconf/pkg-${title}.seeds":
source => "puppet:///modules/desktop/pkg-${title}.seeds",
ensure => present,
}
}
Would like to turn these into one define statement with an optional boolean argument, something like:
define desktop::vinstallopt ( $queryresponse = 'false', ) {
package { $title:
ensure => installed,
allow_virtual => true,
configfiles => keep,
if $queryresponse == 'true' {
require => File["/var/cache/debconf/pkg-${title}.seeds"],
responsefile => "/var/cache/debconf/pkg-${title}.seeds",
}
}
file { "/var/cache/debconf/pkg-${title}.seeds":
source => "puppet:///modules/desktop/pkg-${title}.seeds",
ensure => present,
}
}
and then instantiate it with statements like this one in init.pp:
#desktop::vinstallopt { 'gdebi': queryresponse => 'false', }
But doing so gives an error:
Error: Could not retrieve catalog from remote server: Error 400 on SERVER: Puppet::Parser::AST::Resource failed with argument error ArgumentError: Invalid resource type desktop::vinstallopt at /etc/puppet/modules/desktop/manifests/init.pp:40 on node machine.prvt.net
where line 40 has the syntax above. I'm a newbie with puppet, so my apologies if this turns out the be a simple syntax question. I've tried to find a way to make this work from the PuppetLabs documentation and from other puppet users, so far without luck.
You are trying to embed an if block inside a resource declaration. Alas, this is not possible. The block must be global or in a regular block (e.g., class body, define body, lambda body).
In this case, you want to "amend" the package resource, so to speak. I like to use the following construct for this purpose:
package { $title:
ensure => installed,
allow_virtual => true,
configfiles => keep,
}
if $queryresponse {
Package[$title] {
require => File["/var/cache/debconf/pkg-${title}.seeds"],
responsefile => "/var/cache/debconf/pkg-${title}.seeds",
}
}
Please note that this override syntax is only allowed in this scope because the require and responsefile attributes don't have any value assigned originally.
Trying to do something like this:
# nodes.pp
node 'dev-a-1.sn1.vpc1.example.com' inherits project_j1n_sn1_vpc1_dev {
class { 'custom::core':
overrides => {
'openssh' => {'settings' => {'external_access' => 'true'}}, # Allow direct mounting for dev
'rsyslog' => {'settings' => {'role' => 'node', 'filters' => {'php' => {'target' => 'remote'}, 'mail' => {'target' => 'remote'}}}}
}
}
}
# custom::core
class custom::core($overrides = {}) {
if (has_key($overrides, 'openssh')) {
$settings = $overrides['openssh']['settings']
# Doesn't work
create_resources('openssh', $settings)
# Doesn't work
class { 'openssh': $settings }
}
}
Is it possible to call a class and pass a hash as the arguments?
Puppet/Puppetmaster v2.7.26-1 (Centos 6.7)
There is a way in Puppet 4+.
class { 'ssh':
* => $settings
}
Learn all about it on roidelapluie's blog.
A co-worker of mine had come up with a good solution to something similar in the old 2+ days of puppet. Utilized create_resources for this.
http://www.followski.com/quick-note-how-to-use-create_resources-to-initialize-a-class-in-puppet/
your code can look something like this:
nodes.pp
node 'dev-a-1.sn1.vpc1.example.com' inherits project_j1n_sn1_vpc1_dev {
class { 'custom::core':
overrides => {
'openssh' => {'settings' => {'external_access' => 'true'}}, # Allow direct mounting for dev
'rsyslog' => {'settings' => {'role' => 'node', 'filters' => {'php' => {'target' => 'remote'}, 'mail' => {'target' => 'remote'}}}}
}
}
}
custom::core
class custom::core($overrides = {}) {
if (has_key($overrides, 'openssh')) {
$settings = $overrides['openssh']['settings']
create_resources('class', { 'openssh' => $settings })
}
}
You will notice that in the example linked above it looks like create_resources('class', $params), but that assuming you have a hash with a key being the class name (ie openssh) and its value being the params to set. The example I state above essentially does the same thing.
Your node definition can also be look like this:
node 'dev-a-1.sn1.vpc1.example.com' inherits project_j1n_sn1_vpc1_dev {
class { 'custom::core':
overrides => {
'openssh' => {'external_access' => 'true'}, # Allow direct mounting for dev
'rsyslog' => {'role' => 'node', 'filters' => {'php' => {'target' => 'remote'}, 'mail' => {'target' => 'remote'}}}
}
}
}
and your class something like this:
class custom::core($overrides = {}) {
if (has_key($overrides, 'openssh')) {
create_resources('class', {'openssh' => $overrides['openssh'])
}
if (has_key($overrides, 'rsyslog')) {
create_resources('class', {'rsyslog' => $overrides['rsyslog'])
}
}
I think you get the point by now.
We used this quite often a few years ago. You may want to consider moving towards an upgrade of your puppet infrastructure however.
Hope this helps, or at least points you in the right direction.
Trying to use hiera with puppet. And i'm wondering how could i move something like this to hiera:
Definition:
define apache::namevirtualhost {
$addr_port = $name
# Template uses: $addr_port
concat::fragment { "NameVirtualHost ${addr_port}":
target => $apache::ports_file,
content => template('apache/namevirtualhost.erb'),
}
}
Then in my super_node.pp:
apache::namevirtualhost { '*:80': }
How could i move '*:80' to hiera json file? Something like this (does not seem to work):
{
"apache::namevirtualhost" : "*:80"
}
Same question if i include definitions multiple times, how could i move configuration to hiera:
vagrant::box { 'dev.local':
sshport => '2223',
ip => '10.69.69.101'
}
vagrant::box { 'it.local':
sshport => '2224',
ip => '10.69.69.102'
}
Simply use the hiera function in your manifests, so in your super_node.pp:
$namevirtualhost = hiera("apache::namevirtualhost")
apache::namevirtualhost { $namevirtualhost : }
Same for your boxes:
vagrant::box { 'dev.local':
sshport => hiera("dev_local_sshport"),
ip => hiera("dev_local_ip"),
}
First you should ensure that hiera database is properly configured by typing
hiera "apache::namevirtualhost"
From command_line