Puppet defined resources and hiera json - puppet

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

Related

Configure remote rulesets with Puppet

I'm trying to automate the Prometheus node_exporter and my Prometheus Server.
For the node_exporter I've written a module to install all the needed packages, set the $::ipaddress based on facter and some more..
Now I'd like to make sure that the collected informations ($hostname, $job_name, [...]) from the applying node are exported into the respective remote Prometheus configfile, but I want to have this step done asynchronously, so for example with a puppet agent run afterwards on the Prometheus Server.
I've tried to orientate the classes towards the puppetlabs/logrotate module, which is basically doing the following:
logrotate/init.pp
class logrotate (
String $ensure = present,
Boolean $hieramerge = false,
Boolean $manage_cron_daily = true,
Boolean $create_base_rules = true,
Boolean $purge_configdir = false,
String $package = 'logrotate',
Hash $rules = {},
) {
do some stuff
}
logrotate/rules.pp
class logrotate::rules ($rules = $::logrotate::rules){
#assert_private()
create_resources('logrotate::rule', $rules)
}
logrotate/rule.pp
define logrotate::rule(
Pattern[/^[a-zA-Z0-9\._-]+$/] $rulename = $title,
Enum['present','absent'] $ensure = 'present',
Optional[Logrotate::Path] $path = undef,
(...)
) {
do some stuff
}
Shortened my ni_trending (node_exporter) & ni_prometheus modules currently look very similar to logrotate:
ni_trending/init.pp
class ni_trending (
$hostname = $::fqdn,
$listen_address = $::ipaddress,
$listen_port = 51118,
) {
) inherits ni_trending::params {
anchor { 'ni_trending::start': }
->class { 'ni_trending::package': }
->class { 'ni_trending::config':
(...)
listen_address => $listen_address,
listen_port => $listen_port,
(...)
}
->class { 'ni_trending::service': }
->class { ' ni_trending::prometheus':
(...)
hostname => $hostname,
listen_port => $listen_port,
(...)
}
->anchor { 'ni_trending::end': }
}
ni_trending/prometheus.pp
class ni_trending::prometheus (
Hash $options = {},
) {
ni_prometheus::nodeexporterrule { 'node_exporter' :
ensure => pick_default($options['ensure'], 'present'),
hostname => pick_default($options['hostname'], $ni_trending::hostname),
listen_port => pick_default($options['hostname'], $ni_trending::listen_port),
}
}
ni_prometheus/nodeexporterrules.pp
class ni_prometheus::nodeexporterrules ($rules = $::ni_prometheus::nodeexporterrules) {
create_resources('ni_prometheus::nodeexporterrule', $nodeexporterrules)
}
ni_prometheus/nodeexporterrule.pp
define ni_prometheus::nodeexporterrule (
$job_name = $title,
Enum['present','absent'] $ensure = 'present',
$hostname = $hostname,
$listen_port = $listen_port,
) {
file_line { "prometheus-${job_name}" :
path => "/etc/prometheus/${job_name}.list",
after => 'hosts:',
line => "${hostname}:${listen_port}",
}
}
But this will just work when I apply the node_exporter locally on the Prometheus Master - not in the case that an external machine has the ni_trending::prometheus class included, which makes sense to me - because it clearly feels that something is missing. :-) How can I get this working?
Thanks!
This sounds like a job for exported resources (that makes two in one day!). This is a facility for one node's catalog building to generate resources that can be applied to other nodes (and also, optionally, to the exporting node itself). I'm still not tracking the details of what you want to manage where, so here's a more generic example: maintaining a local hosts file.
Generic example
Suppose we want to automatically manage a hosts file listing all our nodes under management. Puppet has a built-in resource, Host, representing one entry in a hosts file. We make use of that by having every node under management export an appropriate host resource. Something like this would go inside a class included on every node:
##host { "$hostname": ip => $ipaddress; }
The ## prefix marks the resource as exported. It is not applied to the current target node, unless by the mechanism I will describe in a moment. the $hostname and $ipaddress are just facts presented by the target node, and they are resolved in that context. Note, too, that the resource title is globally unique: each target node has a different hostname, therefore all the exported Host resources that apply to different target nodes will have distinct titles.
Then, separately, every node that wants all those Host entries applied to it will import them in its own catalog by using an exported resource collector:
<<|Host|>>
The nodes that export those resources can also collect some or all of them. Additionally, there are ways to be more selective about which resources are collected; see the link above.

Adding custom server options with puppetlabs mysql module

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',
}

conditional within define in puppet

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.

Function contain() vs. Anchor Pattern in Puppet

This post refers to Puppet "require" not working as expected.
Is it possible to replace the Anchor Pattern with the function contain maintaining execution order and hinder declared classes of floating out. The two manifests look as follows:
class profile::maven inherits profile::base {
# Hiera
$version = hiera('profile::maven::version', '3.2.1')
$settings = hiera_hash('profile::maven::settings', undef)
$environments = hiera_hash('profile::maven::environments', undef)
include 'profile::java'
anchor { 'profile::maven::begin': }
class { '::maven::maven': version => $version, }
anchor { 'profile::maven::end': }
if ($settings) {
create_resources('::maven::settings', $settings)
}
if ($environments) {
create_resources('::maven::environment', $environments)
}
Anchor['profile::maven::begin'] -> Class['profile::java'] -> Class['::maven::maven'] -> Anchor['profile::maven::end']
}
and
class profile::java inherits profile::base {
# Hiera
$distribution = hiera('profile::java::distribution', 'jdk')
$version = hiera('profile::java::version', 'present')
anchor { 'profile::java::begin': }
class { '::java':
distribution => $distribution,
version => $version,
}
anchor { 'profile::java::end': }
# Parameters
$java_home = $::java::java_home
file { 'profile-script:java.sh':
ensure => present,
path => '/etc/profile.d/java.sh',
content => template('profile/java.sh.erb'),
}
Anchor['profile::java::begin'] -> Class['::java'] -> File['profile-script:java.sh'] -> Anchor['profile::java::end']
}
Because of the current issue PUP-1597 in Puppet 3.6.x, the profile classes have to be renamed, otherwise we get Error: undefined method 'ref' for nil:NilClass. Applying the changes result in:
class profile::mavenp inherits profile::base {
# Hiera
$version = hiera('profile::maven::version', '3.2.1')
$settings = hiera_hash('profile::maven::settings', undef)
$environments = hiera_hash('profile::maven::environments', undef)
include 'profile::javap'
class { '::maven::maven': version => $version, }
contain 'maven::maven'
if ($settings) {
create_resources('::maven::settings', $settings)
}
if ($environments) {
create_resources('::maven::environment', $environments)
}
Class['profile::javap'] -> Class['::maven::maven']
}
and
class profile::javap inherits profile::base {
# Hiera
$distribution = hiera('profile::java::distribution', 'jdk')
$version = hiera('profile::java::version', 'present')
class { '::java':
distribution => $distribution,
version => $version,
}
contain 'java'
# Parameters
$java_home = $::java::java_home
file { 'profile-script:java.sh':
ensure => present,
path => '/etc/profile.d/java.sh',
content => template('profile/java.sh.erb'),
}
}
Are these changes equivalent?
If someone has a better idea of how to the deal with technologcial dependencies in Puppet using the profile/role approach, do not hesitate to share your thoughts.
The latter pair of classes are not completely equivalent equivalent to the former. The biggest issue is in profile::javap. Note that its analog profile::java has this as part of its dependency chain:
Class['::java'] -> File['profile-script:java.sh']
Class profile::javap has no analog of that.
I'm not 100% certain whether class profile::mavenp is equivalent to class profile::maven, though I think it is. Your intent would be clearer and my uncertainty would be resolved if the former included
contain 'profile::javap'
instead of (or in addition to)
include 'profile::javap'

Is it possible to define a list of Defined Resource in Puppet?

Let's say for example I have 3 servers, those 3 servers has apache installed.
For each of them I have to instantiate several apache::vhost defined resource.
Is there any way that instead of doing that
node 'srv1.example.com' inherit webserver {
apache::vhost { 'toto1' :
... => ... ,
}
apache::vhost { 'toto2' :
... => ... ,
}
apache::vhost { 'toto3' :
... => ... ,
}
}
One can do something with the following pattern (admitting that my defined resource just with the name can do what it needs to)
node 'srv1.example.com' inherit webserver {
$vhost = ['toto1', 'toto2', 'toto3'];
??????
}
Yes.
node 'srv1.example.com' inherit webserver {
$vhosts = ['toto1', 'toto2', 'toto3'];
apache::vhost { [$vhosts]:
... => ... ,
}
}
This, of course, requires that everything be the same or be based on the name (which is available as $name inside the apache::vhost define).
If you want to keep apache::vhost as a straightforward define and still do some more complicated things to work out parameters from the name, you can do them with an intermediate define:
define blah::vhost {
$wwwroot = "/var/www/html/blah/${name}"
$wwwhostname = "${name}.example.com"
if ! defined(File[$wwwroot]) {
file { $wwwroot:
ensure => directory,
mode => 0775,
}
}
apache::vhost { $name:
path => $wwwroot,
aliases => [$name],
hostname => $wwwhostname,
require => File[$wwwroot],
}
}
blah::vhost { [$vhosts]: }

Resources