refactor ensure_packages to switch version of installed packages - puppet

I am successfully installing several PHP modules by version with puppet on Debian linux like this:
$php_version = '7.3'
ensure_packages([
"php$php_version-xml",
"php$php_version-zip",
"php$php_version-curl",
"php$php_version-mbstring",
"libapache2-mod-php$php_version",
],
{
'ensure' => 'present',
}
)
now I want to prepare for an update from PHP 7.3 to 7.4. This basically works, but the 7.3 packages stay installed. I would like to adapt the code to remove the old packages. I am looking for a way to reuse the list of packages of modules for uninstalling.
I am thinking of a signature like this
class profile::software::apache (
$php_version = '7.4',
$php_remove = ['7.0‘, ‘7.3'],
#...
) {
$myPackages = [
"php$php_version-xml",
"php$php_version-zip",
"php$php_version-curl",
"php$php_version-mbstring",
"libapache2-mod-php$php_version",
]
ensure_packages($myPackages,
{
'ensure' => 'present',
}
)
$php_remove.each | String $php_version | {
ensure_packages($myPackages,
{
'ensure' => 'absent',
}
)
}
}
Is there a way to solve this?
thx

I was able to solve this by using iteration functions of puppet.
From the two parameters I build a hash with keys of versions to work on and values to either install or remove the given version.
Now I can iterate over this hash with each, reusing the structure:
class profile::software::apache (
$php_version = '7.4',
$php_remove = ['7.0‘, ‘7.3'],
#...
) {
# build a hash of PHP Versions with a value of either present or absent
# and iterate over it with each
$phpInstallHash = { $php_version => 'present' }
#notify { "Value of phpRemove: ${php_remove}": }
if $php_remove {
# We have the array, use the map function to build remove hash
$phpRemoveHash = $php_remove.map |$version| {
{ $version => 'absent' }
}
$phpFullHash = $phpInstallHash + $phpRemoveHash
} else {
$phpFullHash = $phpInstallHash
}
#notify { "phpHash to iterate over to install/uninstall: ${phpFullHash}": }
#iterate over the result installing/uninstalling
$phpFullHash.each | $php_version, $ensure_value | {
ensure_packages([
"php$php_version-xml",
"php$php_version-zip",
"php$php_version-curl",
"php$php_version-mbstring",
"libapache2-mod-php$php_version",
],
{
'ensure' => $ensure_value,
require => [Class['apt::update'],
Apt::Source['source_php_sury'],
],
notify => Class['apache::service'],
}
)
}
}
hth

Related

Overriding a Puppet Class when using Inheritance

I'm trying to use class inheritance for puppet. There is a base class named foo and an inherited class named bar. Overriding file or package resources are quite fine and works properly. But at the same time i'm using a custom module for configuring sudo.
The problem arises when i try to override sudo class from inside class bar. Puppet classes are as follows:
class foo {
$nrpe_plugin_pkgs = [ .... ]
service { 'nrpe service':
..
}
package { $nrpe_plugin_pkgs:
..
}
file { '/etc/nagios/nrpe.cfg':
..
}
file { '/etc/resolv.conf':
..
}
class { 'sudo':
purge => true,
config_file_replace => true,
}
sudo::conf { 'sudo_conf':
priority => 10,
content => [
'%gr1 ALL=(userfoo) NOPASSWD: ALL',
'%gr1 ALL=(root) NOPASSWD: /usr/bin/wbinfo *',
]
}
}
class bar inherits foo {
File['/etc/resolv.conf'] {
..
}
sudo::conf { 'sudo_conf':
priority => 10,
content => [
'%gr2 ALL=NOPASSWD:/bin/chown userbar\:gr2 /dirbar/*',
'%gr2 ALL=NOPASSWD:/bin/chown -R userbar\:gr2 /dirbar/*',
'%gr2 ALL=NOPASSWD:/bin/chmod * /dirbar/*',
]
}
}
I just want to customize only resolv.conf and sudo config, but i'm getting error as follows:
Error while evaluating a Resource Statement, Evaluation Error: Error
while evaluating a Resource Statement, Duplicate declaration:
Sudo::Conf[sudo_conf] is already declared in file
/etc/puppetlabs/code/environments/foobar_servers/manifests/foobar.pp:80;
cannot redeclare at
/etc/puppetlabs/code/environments/foobar_servers/manifests/foobar.pp:335
at
/etc/puppetlabs/code/environments/foobar_servers/manifests/foobar.pp:335:3
on node foobartest01
/etc/sudoers.d/10_sudo_conf file expected to be created. How can i achieve that?
Using: Puppet 4.9 Community version.
Any help appreciated.
The resolv.conf override works here, because you're using the correct syntax:
class bar inherits foo {
File['/etc/resolv.conf'] {
..
}
But the syntax for the next line where you try to override is different, so it fails:
sudo::conf { 'sudo_conf':
This is the syntax to declare a new resource (hence why you get a duplicate error) rather than to override an existing resource. It should be:
Sudo::Conf['sudo_conf'] {
priority => 10,
content => [
'%gr2 ALL=NOPASSWD:/bin/chown userbar\:gr2 /dirbar/*',
'%gr2 ALL=NOPASSWD:/bin/chown -R userbar\:gr2 /dirbar/*',
'%gr2 ALL=NOPASSWD:/bin/chmod * /dirbar/*',
]
}

Puppet Error: You cannot specify more than one of content, source, target

I am trying to create one file and one symbolic link via Puppet (with Hiera). I'm running on Ubuntu 16.04, and I am using all latest modules.
The file is called "a" and the link is called "b". These files are not related directly.
I have a init.pp file for the node:
define hiera::files (
$ensure,
$content= "",
$target="/./.",
$mode = "",
$owner = "root",
$force = "false" ) {
file { $title:
ensure => $ensure,
owner => $owner,
force => $force,
content => $content,
mode => $mode,
target => $target,
}
}
create_resources('hiera::files', hiera_hash('files', {}))
node "default" {
hiera_include('classes')
}
There is also a node.yaml file containing the corresponding data:
files:
/etc/a.txt:
ensure: "present"
mode: "2770"
owner: "simon"
content: "[d] \n type = sss \n resource = samba_1"
/etc/b:
ensure: "link"
target: "/usr/share/b"
mode: "777"
I have tried other variations, but I always get an error that I cannot specify more than one of content, source, target. Is it possible to have both? Not for the same file, but for separate files like I am trying to do?
The hiera::files defaults are the issue here, as even if you're not specifying content and target in your Hiera hash, they're being set:
define hiera::files ( $ensure, $content= "", $target="/./.", $mode = "", $owner = "root", $force = "false" ){
Change the $content and $target defaults to undef so they must be specified if you're going to use them.
define hiera::files ( $ensure, $content = undef, $target = undef, $mode = "", $owner = "root", $force = "false" ){
If you really need these default values, then you need a way to avoid setting target on a file with content, and content on a file/symlink with target, e.g.
define hiera::files ( $ensure, $content = undef, $target = undef, $mode = "", $owner = "root", $force = "false" ){
# Provide a default empty content value when ensure => present, and no content is given
$real_content = $ensure ? {
"present" => $content ? {
undef => "",
default => $content,
},
default => undef,
}
# Provide a default /./. target value when ensure => link, and no target is given
$real_target = $ensure ? {
"link" => $target ? {
undef => "/./.",
default => $target,
},
default => undef,
}
file { $title:
ensure => $ensure,
owner => $owner,
force => $force,
content => $real_content,
mode => $mode,
target => $real_target,
}
}
Or perhaps preferably, use separate defines to make the behaviour clear.

pass array to the puppet resource defined

I would like to test if multiple packages exist in my environment or not, based on this test I would like to generate the final catalog.
if !defined( Package[ 'apache2' ] ) {
package { 'apache2':
ensure => installed,
}
}
if !defined( Package[ 'libapache2-svn' ] ) {
package { 'libapache2-svn':
ensure => installed,
}
}
In future I would like to control in the following way:
Package { ensure => "installed" }
$packageList = [ 'apache2', 'libapache2-svn' ]
if !defined( Package[ $packageList ] ) {
package { $packageList: }
}

Cannot parse array into defined type

I am using following puppet class
class myclass{
$foo = [{"id" => "bar", "ip" => "1.1.1.1"}, {"id" => "baz", "ip" => "2.2.2.2"}]
map {$foo:}
define map () { notify {$name['id']: } }
}
But this gives me
err: Could not retrieve catalog from remote server: Could not intern from pson: Could not convert from pson: Could not find relationship target "Change_config::Map[ip1.1.1.1idbar]"
warning: Not using cache on failed catalog
err: Could not retrieve catalog; skipping run
What is the reason for this ?
Regards,
Malintha Adikari
Your array contains hashes. The resource declaration syntax works only for arrays of strings.
$foo = ["bar", "baz"]
map {$foo:}
define map () { notify {$name: } }
If you want to pass data with each resource title, you need to
build a hash of your data, not an array of hashes
use the create_resources function
Untested example code:
$foo = {
"bar" => { "ip" => "1.1.1.1" },
"baz" => { "ip" => "2.2.2.2" },
}
create_resources('map', $foo)
define map ($ip="") { notify { "$name has ip $ip": } }

Groovy - How to simplify embedded function arguments

I am running groovy in jenkins and I want to split the data from the functionality. I've tried to create a map with variable names and values but it looks like functions inside functions screws that up. I want to pull out CurrentBuildNo, ProjectName, Results_Folder (they are different for each parallel run) without duplicating code.
autotests = parallel (
{ ignore(ABORTED) {
retry ( 2 ) {
build("AutoTest", CurrentBuildNo: CurrentBuildNo, ProjectName: params["ProjectName"], Results_Folder: Results_Folder)
} } },
{ ignore(ABORTED) {
retry ( 2 ) {
build("AutoTest", CurrentBuildNo: CurrentBuildNo, ProjectName: params["ProjectName"], Results_Folder: Results_Folder)
} } }
)
The logic I want is something like:
tests = {{CurrentBuildNo: CurrentBuildNo, ...},{CurrentBuildNo: CurrentBuildNo, ...}}
autotests = parallel (
for (i in tests){
ignore(ABORTED) {
retry ( 2 ) {
build("AutoTest", test[i]['CurrentBuildNo'], test[i]['ProjectName']...)
} } }
}
)
Ahhh, I think you'll want something like this:
def tests = [ [ CurrentBuildNo: CurrentBuildNo, ... ],
[ CurrentBuildNo: CurrentBuildNo, ... ] ]
parallel tests.collect { t ->
{
ignore( ABORTED ) {
retry( 2 ) {
build( 'AutoTest', t.CurrentBuildNo, ... )
}
}
}
}

Resources