Function contain() vs. Anchor Pattern in Puppet - 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'

Related

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 manifest not running

I used to just include all of my puppet modules like so:
include user_manager
include pp_package_manager
include ppcc_code_manager
include ppcc_backup
include pp_db_manager
include pp_apache_manager
include pp_rabbit_manager
include pp_salt_manager
include pp_freeswitch_manager
include ppcc_services_manager
This caused lots of dependency problems and I had to run the puppet agent multiple times before they would all resolve themselves. I then tried using Stages to clean that up, resulting in this:
stage { 'code': require => Stage['main'], before => Stage['backup'], }
stage { 'backup': before => Stage['big-packages'], }
stage { 'big-packages': before => Stage['freeswitch'], }
stage { 'freeswitch': before => Stage['services'] }
stage { 'services': }
node 'blah.example.com' {
class { 'pp_package_manager': stage => 'main', }
class { 'user_manager': stage => 'main', }
class { 'ppcc_code_manager': stage => 'code', }
class { 'ppcc_backup': stage => 'backup', }
class { 'pp_db_manager': stage => 'big-packages', }
class { 'pp_apache_manager': stage => 'big-packages', }
class { 'pp_rabbit_manager': stage => 'big-packages', }
class { 'ppcc_services_manager': stage => 'services', }
class { 'pp_salt_manager': stage => 'big-packages', }
class { 'pp_freeswitch_manager': stage => 'freeswitch', }
}
I even tried putting everything in the node definition, using arrow notation, defining the stages before and then using arrow notations. Each time, nothing happened. No errors, just nothing. Even using --debug, the puppet agent would just... stop.
Finally, I just tried using arrow notations between each of the class declarations.
class { 'user_manager': } ->
class { 'pp_package_manager': } ->
class { 'ppcc_code_manager': } ->
class { 'ppcc_backup': } ->
class { 'pp_db_manager': } ->
class { 'pp_apache_manager': } ->
class { 'pp_rabbit_manager': } ->
class { 'pp_salt_manager': } ->
class { 'pp_freeswitch_manager': } ->
class { 'ppcc_services_manager': }
That didn't run either. I'm pretty much all out of ideas now. Why is nothing happening when I run the puppet agent? What am I doing wrong?
I can't really comment on the issues without seeing what your manifests look like.
But I think there is something that could help you: Have you read about the roles and profiles pattern? It helps with these kind of design issues and helps narrowing down which manifests are causing problems.
It also allows you to apply testing to each component or group of components, so you can narrow down what the issue is that's causing the agent not to run.
Some example posts about it here:
https://puppetlabs.com/presentations/designing-puppet-rolesprofiles-pattern
http://garylarizza.com/blog/2014/02/17/puppet-workflow-part-2/
http://rnelson0.com/2014/07/14/intro-to-roles-and-profiles-with-puppet-and-hiera/

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

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