Puppet - Variable for package name fails - puppet

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

Related

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.

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

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'

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