How to exclude calling class in puppet based on the command execution? - puppet

In the puppet script I inherited there is a class pyenv for pyenv installation
class pyenv(
include ::pyenv
$ensure_repo = 'present',
$repo_location = '/usr/local/pyenv',
$repo_revision = 'v0.4.0-20140404',
$symlink_pyenv = true,
$symlink_path = '/usr/local/bin',
$manage_packages = true,
$ensure_packages = 'latest',
$python_build_packages = $::pyenv::params::python_build_packages,
)
It does not work well. So, I changed installation to the regular script pyenv installation and would like to exclude calling this class in the following class python.
First, I excluded it by simply commenting out:
class python {
# class { '::pyenv': } ->
# pyenv_python { '2.7.9': }
# exec { 'set-python-global':
# command => '/usr/local/bin/pyenv global 2.7.9',
# user => root,
# require => Class['::pyenv'],
# } ->
exec { 'install-boto':
command => '/root/.pyenv/shims/pip install boto',
user => 'root',
unless => '/root/.pyenv/shims/pip freeze | grep boto',
} ->
Is there more intelligent way of excluding? I am thinking that if pyenv is already installed and setting global pyenv version is successful do not call class pyenv? Please, note that pyenv is not now in the /usr/local/bin although I can create a symbolic link.

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.

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

How to handle linux and windows in puppet modules?

I have a large Module written for linux systems. But I need it to work for windows so I want to rewrite it to handle both.
There are a lot of manifests and from what I can see so far, most of it should be ok with Windows as puppet would see it's running on windows and select the best provider.
However there are some parts that won't work. As an example this exec will not work on windows
exec { 'touch_file' :
command => 'touch /etc/test.txt',
path => ['/bin', '/usr/bin'],
cwd => '/tmp',
creates => '/etc/test.txt',
}
This would work in linux but in Windows I would change this to a powershell command and also change creates, cwd and path. I could change each part to a ${variable} and have a case statement above the Exec statement that picks the right variables based on ::osgroup but I'm not sure if this is the best way to handle this. Is there a better way of handling multi OS modules?
Sometimes it's better to have different execs based on the OS you are targeting. See https://github.com/puppetlabs/puppetlabs-puppet_agent as a good example of this:
https://github.com/puppetlabs/puppetlabs-puppet_agent/blob/f76482b2b68bd80115de87037ba71068bea4e35b/manifests/init.pp#L36-L46
if $::osfamily == 'windows' {
class { '::puppet_agent::prepare': } ->
class { '::puppet_agent::windows::install': }
}
else {
if $::operatingsystem == 'SLES' and $::operatingsystemmajrelease == '10' {
$_package_file_name = "${puppet_agent::package_name}-${puppet_agent::params::master_agent_version}-1.sles10.${::architecture}.rpm"
} elsif $::operatingsystem == 'Solaris' and $::operatingsystemmajrelease == '10' {
$_package_file_name = "${puppet_agent::package_name}-${puppet_agent::params::master_agent_version}-1.i386.pkg.gz"
}
class { '::puppet_agent::prepare':
package_file_name => $_package_file_name,
} ->
class { '::puppet_agent::install':
package_file_name => $_package_file_name,
} ->
class { '::puppet_agent::service': }
contain '::puppet_agent::prepare'
contain '::puppet_agent::install'
contain '::puppet_agent::service'
}

Passing variables between classes in puppet

I am trying to use the exec resource type to execute a batch file. But I want to pass the value of variable $dsn_64bit from init.pp to install.pp. Please let me know how to achieve that:
Here is my init.pp
class exec_batchfile ($dsn_64bit = "false")
{
if $::osfamily == 'windows' {
include exec_batchfile::install
}
}
Here is my install.pp
class exec_batchfile::install
{
if $dsn_64bit == true
{
$hklm_path = 'HKLM\Software\Oracle'
$Script_name = 'E:\\Path\\pupp_test64.bat'
}
else
{
$hklm_path = 'HKLM\Software\WOW6432Node\Oracle'
$Script_name = 'E:\\Path\\pupp_test.bat'
}
exec { 'exec_batchfile':
command => "${Script_name}",
path => $::path,
logoutput => true,
unless => "cmd.exe /c reg query ${hklm_path} /v inst_loc",
}
}
Thanks
Since puppet 2.7 dynamic lookup is deprecated, so your code will not work properly. Right now the recommended solution is to use fully qualified names. Please follow the link to find a comprehensive explanation.
Whenever you need to refer to a variable in another class, give the variable an explicit namespace: instead of simply referring to $packagelist, use $git::core::packagelist.

Puppet - Variable for package name fails

I'm new to puppet, and I am stumped.
I am installing gcc, gcc-c++, openssl and openssl-devel.
In the code shown, $openssl_devel works but $c_plus is undefined.
Why is puppet setting $c_plus to 'undef' ?
Cent OS 6
class torque::prerequisites {
case $operatingsystem {
centos,redhat: {$openssl_devel = 'openssl-devel'}
centos,redhat: {$c_plus = 'gcc-c++'}
debian,ubuntu: {$openssl_devel = 'libssl-dev'}
debian,ubuntu: {$c_plus = 'build-essential'}
default:{fail("Unable identify opperating system. $operatingsytem not recognized") }
}
package {'openssl':
ensure => latest,
}
package {$openssl_devel:
ensure => latest,
require => Package['openssl'],
}
package {'gcc':
ensure => installed,
}
package {$c_plus:
ensure => installed,
require => Package['gcc'],
}
}
class {'torque::prerequisites':}
puppet apply torque_prerequisites
err: /Stage[main]/Torque::Prerequisites/Package[undef]/ensure: change from absent to present failed: Could not find package undef
I still don't know why the original syntax didn't work, but this syntax does works:
class torque::prerequisites {
case $::osfamily {
Redhat: {
$openssl_devel = 'openssl-devel'
$c_plus_compiler = 'gcc-c++'
}
Debian: {
$openssl_devel = 'libssl-dev'
$c_plus_compiler = 'build-essential'
}
default:{fail("Unable identify opperating system. $operatingsytem not recognized") }
}
package {'openssl':
ensure => latest,
}
package {$openssl_devel:
ensure => latest,
require => Package['openssl'],
}
package {'gcc':
ensure => installed,
}
package {$c_plus_compiler:
ensure => installed,
require => Package['gcc'],
}
}
class {'torque::prerequisites':}

Resources