Configure remote rulesets with Puppet - 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.

Related

puppet creating relationship between file, class and define

I want to create relationship between file, class and define.... Please check the below code....
The problem I am facing is, even if there is no change in deploy.cfg file, class and nexus::artifact always runs...
class and nexus::artifact should execute only if it detects a change in file
I know that we need to make use of subscribe and refreshonly=true. But I have no idea where to put this...
file { 'deploy.cfg':
ensure => file,
path => '/home/deploy/deploy.cfg',
mode => '0644',
owner => 'root',
group => 'root',
content => "test",
notify => [Class['nexus'], Nexus::Artifact['nexus-artifact']],
subscribe => File['/home/deploy/dir'],
}
class { 'nexus':
url => $url,
username => $user,
password => $password,
}
nexus::artifact { "nexus-artifact":
gav => $gav,
packaging => $packaging,
output => $targetfilepath,
repository => $repository,
owner => $owner,
mode => $mode,
}
artifact.pp
define nexus::artifact (
$gav,
$repository,
$output,
$packaging = 'jar',
$classifier = undef,
$ensure = update,
$timeout = undef,
$owner = undef,
$group = undef,
$mode = undef
) {
include nexus
}
init.pp
class nexus (
$url,
$username = undef,
$password = undef,
$netrc = undef,
) {
}
even if there is no change in deploy.cfg file, class and nexus::artifact always runs
Well yes, every class and resource in your node's catalog is applied on every catalog run, unless a resource that is required to be applied before it fails. That is normal. The key thing to understand in this regard is that the first part of applying a catalog resource is determining whether the corresponding physical resource is already in sync; if it is, then applying the catalog resource has no further effect.
class and nexus::artifact should execute only if it detects a change in file
I know that we need to make use of subscribe and refreshonly=true.
Well, no. You may be able to modulate the effect of applying that class and resource, but you cannot use the result of syncing another resource to modulate whether they are applied at all. In any event, refreshonly is specific to Exec resources, and you don't have any of those in your code.

puppet defined types and variables

I am new to puppet and I am trying to write a module to manage .bashrc file of 10 users. The following code is ok to manage the file of 1 user. However, I am unable to change the code to manage files for 10 users. I tried using defined types and variable with no luck. Can sombody please suggest me the right way to do this.
init.pp:
class profile (
$bashrc = $profile::params::bashrc,
$bashrc_host = $profile::params::bashrc_host,
) inherits profile::params {
anchor { 'profile::begin': } ->
class { '::profile::config': } ->
anchor { 'profile::end': }
}
config.pp:
class profile::config inherits profile {
file { $bashrc:
ensure => file,
source => "puppet:///$bashrc_host",
}
params.pp:
class profile::params {
$bashrc_host = "modules/profile/$fqdn_user1_bashrc"
}
case $::osfamily {
'RedHat': {
$bashrc = '/home/user1/.bashrc'
}
}
This is not at all a job for a class. As you noted yourself in your most recent comment, this calls for a define actually.
Please don't use verbs in the names of your defines. Instead of defineuser, just do
define profile::user($host_name) {
}
Off the top of my hat, I'm not aware of a good pattern to use module parameters in your defines. You can however use the following pattern:
class profile(
$default_shell = $profile::params::default_shell,
$default_prompt = $profile::params::default_prompt,
$users = {}
) inherits profile::params {
$defaults = { shell => $default_shell, prompt => $default_prompt }
create_resources('profile::user', $users, $defaults)
}
What happens is
values are taken from params, or hiera, or the invoking manifest
these values are gathered in the $defaults array
for any resource in the $users hash that has no shell or prompt, this default is used
If your aim of this module is to learn puppet then:
Add a param user to your class profile::params
class profile::params {
$bashrc_host = "modules/profile/$fqdn_user1_bashrc"
$user = 'user1',
}
case $::osfamily {
'RedHat': {
$bashrc = "/home/$user/.bashrc"
}
}
After this, you can use a combination of array or hiera and ensure_resource This still is not the most elegant solution, but baby steps.
If your intend is to actually manage the bashrc for various users, I would recommend using a pre existing module such as account

Puppet variable immutability

There is a language pattern I would like to use in puppet and am having trouble figuring out how to implement it. Let's say I have a parameterized class:
class ntp (
$ensure = 'present',
$ntp_package_ensure = 'present',
$ntp_package_name = 'ntp',
$ntp_config_ensure = 'file',
$ntp_config_path = '/etc/ntp.conf',
$ntp_service_ensure = 'running',
$ntp_service_enable = true,
$ntp_service_name = 'ntpd',
) {
I would then really like to be able to say:
if $ensure == 'absent' {
$ntp_package_ensure = 'absent',
$ntp_config_ensure = 'absent',
$ntp_service_ensure = 'stopped',
}
But because puppet variables (constants?) are immutable I'm getting syntax errors. So What is puppets way of doing this? The only solution I can see right now is to add a monolith if statement that partitions the code into an ensure section and an else section.
The most straight forward workaround is to actually introduce new local variables.
case $ensure {
'absent': {
$my_ntp_package_ensure = 'absent'
$my_ntp_config_ensure = 'absent'
$my_ntp_service_ensure = 'stopped'
}
'present': {
...
}
default: {
$my_ntp_package_ensure = $ntp_package_ensure
$my_ntp_config_ensure = $ntp_config_ensure
$my_ntp_service_ensure = $ntp_service_ensure
}
}
Then only use the local counterparts instead of the parameters proper.
I recommend to refrain from such an API design and instead ask a new question concerning the actual scenario and how to structure the ntp module better.

Puppet defined resources and hiera json

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

Defining and calling function in puppet 2.6 and 2.7

I have a module core and a class core::logrotate defined in core/manifests/logrotate.pp.
class core::logrotate {
#...some stuff here
#
define confd ($ensure = "present" , $log_name = "dummy" ) {
if ( $ensure == present )
{
file {
"/etc/logrotate.d/$log_name":
ensure => present,
source => filelookup("core/${log_name}.logrotate"),
}
} else {
file {
"/etc/logrotate.d/$log_name":
ensure => absent,
}
}
}
}
calling this function inside of templates.pp as
core::logrotate::confd { "mkill": log_name => mkill }
This fails with the error
Error 400 on SERVER: Puppet::Parser::AST::Resource failed with error ArgumentError: Invalid resource type core::logrotate::confd
If the puppet master version is 2.6.x then this fails, to make it work there used to be a import "*" in the init.pp of the module. Now removed this as moving to puppet 2.7.20.
The code pasted here works in 2.7 but fails in 2.6. Any idea why? how can I make it work for both 2.6 and 2.7?
You should take the define outside of the class, see the style guide: http://docs.puppetlabs.com/guides/style_guide.html#classes
Also, I think that you might be using modules wrong, it would be much more logical to have a 'logrotate' module on its own.
So; in modulepath/logrotate/manifests/confd.pp you'd put this:
define logrotate::confd ($ensure = "present" , $log_name = "dummy" ) {
if ( $ensure == present )
{
file {
"/etc/logrotate.d/$log_name":
ensure => present,
source => filelookup("core/${log_name}.logrotate"),
}
} else {
file {
"/etc/logrotate.d/$log_name":
ensure => absent,
}
}
}
That should make it work properly.
Greetings,
Ger

Resources