Puppet parameterized classes and changing parameters - class

I am trying to understand Puppet parameterized classes. I have a parameterized class defined this way:
class defaults(
$no_samba = 'FALSE'
)
{
if ($no_samba =~ /TRUE/) {
notify { "will not install samba": } ;
} else {
# install samba here
}
# More server install tasks here...
}
Furthermore, I define a basenode as follows:
node basenode
{
class {'defaults':
no_samba => 'FALSE',
}
}
and then I instantiate a server:
node myserver1 inherits basenode {
Class['defaults'] { no_samba => 'TRUE' }
}
However, this does not work. The myserver1 node does not show the notify message indicating that samba will not be installed.

Here's my non-typo answer - I think you're running into http://projects.puppetlabs.com/issues/7890
Here's a code sample where I tweaked your code to get the effect you're looking for, based on the rewritten example in the ticket:
class defaults(
$no_samba = 'FALSE'
)
{
notify {"no_samba_hack" :
message => "$no_samba";
}
if ($no_samba =~ /TRUE/) {
notify { "will not install samba": }
} else {
# install samba here
}
# More server install tasks here...
}
class basenode($no_samba="FALSE") {
class {defaults: no_samba => $no_samba}
}
node yourserver {
class { 'basenode' : no_samba => 'TRUE'}
}
When I run that with 'puppet apply sample.pp' with puppet 2.7.11 on Ubuntu 12.04, I get the following output:
notice: will not install samba
notice: /Stage[main]/Defaults/Notify[will not install samba]/message: defined 'message' as 'will not install samba'
notice: TRUE
notice: /Stage[main]/Defaults/Notify[no_samba_hack]/message: defined 'message' as 'TRUE'
notice: Finished catalog run in 0.05 seconds

Was samba installed on myserver1, and/or did any of the other server install tasks get triggered ? If only the notify message wasn't printed, then it may really be a problem with notify type versus the notice function.
Notify should look like "notify{"i have curly brackets and a trailing colon":}
Notice is called like a function: notice("i use parenthesis")
Try changing 'notify' to 'notice' and see if it works. You may also want to check the puppet syntax with 'puppet parser validate default.pp' (assuming your default class is in default.pp)

I believe it has to do with scope. It looks like you're creating the 'default' class in the base node and then setting a resource default for the 'default' class after the fact in something that inherits that basenode.
http://docs.puppetlabs.com/guides/language_guide.html
"Defaults are not global — they only affect the current scope and scopes below the current one."

Here is simple example:
class apache-setup {
class { 'apache':
mpm_module => 'prefork',
}
}
include apache-setup
Or:
class { '::mysql::server':
config_file => '/etc/my.cnf',
root_password => 'root', # Sets MySQL root password.
override_options => {
'mysqld' => {
'max_connections' => '512',
'max_allowed_packet' => '256M',
'log' => 'ON',
'log_slow_queries' => 'ON',
'general_log' => 'ON',
'wait_timeout' => '28800',
}
}
}

Related

Puppet - restart a service after a each loop

I'm writing a Puppet module to enforce a configuration and restart the service if needed. I'd like to do something like that:
class app_cfg {
$app_files = ['file1', 'file2', 'file3']
$app_files.each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
}
} ~>
service { 'app':
ensure => running,
enable => true,
}
}
I could add "notify" inside the exec but I don't want to restart my service for each file, and it looks like the notify chaining arrow doesn't work after an each loop. Do you guys have any idea how to make it work?
Thanks a lot :)
I found a workaround by inserting a for loop inside the exec resource instead of using each:
class app_cfg {
service { 'app':
ensure => running,
enable => true,
}
exec {"for file in file1 file2 file3; do sed -i 's/bar/foo/g' \$file; done":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
provider => shell,
notify => Service['app']
}
}
I'm still pretty curious about the first solution! Did you ever manage to do something like that?
Thanks!
I could add "notify" inside the exec but I don't want to restart my
service for each file, and it looks like the notify chaining arrow
doesn't work after an each loop.
It is important to understand that the code in a Puppet manifest describes only how to build a catalog that in turn describes the desired configuration of your server. The catalog lists the classes and resources declared, their parameters and properties, and the relationships among them. The logic within a manifest does not map to actions performed when applying the resulting catalog; it is reflected only in which classes and resources are catalogued, and what their parameters, properties, and relationships are.
Thus, when you use one of the chaining arrows in a manifest, you are instructing the catalog builder to record a relationship between the two resources in the catalog, not an explicit instruction to apply or refresh a resource. No declared resource will be applied at more than once or refreshed more times than it is applied. It will be perfectly fine, therefore, to put an appropriate chain expression inside your loop, but what you cannot do is put the Service declaration itself inside the loop, because that would produce multiple declarations of it. So you might do any of these:
Declare the service (once), and use a resource reference to it in your chain expression inside the loop:
class app_cfg {
service { 'app':
ensure => running,
enable => true,
}
['file1', 'file2', 'file3'].each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
} ~> Service['App']
}
}
As above, but use the appropriate resource metaparameter instead of a chain expression:
class app_cfg {
service { 'app':
ensure => running,
enable => true,
}
['file1', 'file2', 'file3'].each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
notify => Service['app'],
}
}
}
Or declare the relationships with the help of a collector:
class app_cfg {
['file1', 'file2', 'file3'].each |String $file| {
exec {"sed -i 's/bar/foo/g' $file":
path => ['/bin'],
onlyif => 'grep "bar" $file 2>/dev/null',
cwd => '/opt/app/config/',
tag => 'app_notifier',
}
}
Exec<|tag == 'app_notifier|>
~> service { 'app':
ensure => running,
enable => true,
}
}

Changing default download directory in Chrome Webdriver

Can anyone let me know how can I change the default download location for Chrome using Selenium-Perl. I am using Chrome Webdriver and the Perl module Selenium::Remote::Driver. I got code for Java but not in Perl for this task.
I do not have the test setup but passing below as desired_capabilities or extra_capabilities to the constructor should work fine.
'download.default_directory', 'C:\New_Folder'
Snippet (untested):
my $driver = Selenium::Remote::Driver->new(
'browser_name' =>'chrome',
'extra_capabilities' => {
'chromeOptions' => {
'prefs' => {
'download.default_directory' => 'C:\New_Folder'
}
}
}
);
Edit: Difference between Selenium::Chrome and Selenium::Remote::Driver
Selenium::Chrome allows you to use the ChromeDriver without needing the JRE or a selenium server running. If the ChromeDriver binary is not found, it falls back to the default Selenium::Remote::Driver.
I had troubles understanding the difference mentioned between Selenium::Chrome and Selenium::Remote::Driver. Here's what I got to work:
my $driver = Selenium::Chrome->new(
extra_capabilities => {
'goog:chromeOptions' => {
prefs => {
'download.default_directory' => '/tmp'
},
args => [ 'window-size=1950,500' ]
}
}
);

How do I ensure a Puppet exec resource always includes `set -o pipefail`?

In a particular project, I have a lot of Puppet exec resources with pipes. This seems to work just fine.
exec { 'foobar':
command => 'foo | bar',
}
However, there are occasions where foo fails. The default behavior is to report the exit code only for the last command in the pipeline. I can fix this manually.
exec { 'foobar':
command => 'set -o pipefail; foo | bar',
provider => shell,
}
But, I want to make sure this happens in all these cases automatically. I'd like to avoid manual find/replace and auditing all uses of exec.
Am I missing some useful attribute?
Is there a wrapper I can use?
Am I, unfortunately, looking at a custom resource?
Am I missing some useful attribute?
No, Exec has no attribute that would automatically prepend additional code to the command.
Is there a wrapper I can use?
I'm not confident I understand what you mean by a "wrapper", but do see below.
Am I, unfortunately, looking at a custom resource?
If you're asking whether you need to implement a native custom type, then surely not. You can undoubtedly address this problem with a (DSL-level) defined type, though you will need to adjust all your Exec declarations to be declarations of the defined type instead. This may be what you mean by a "wrapper" -- I'm fairly sure there's no existing one for your particular purpose, but it shouldn't be hard to create one:
define mymodule::exec (
command => $title,
creates => 'NOT SET',
cwd => 'NOT SET',
# ... all other regular parameters ...
) {
$real_provider = $provider ? { 'NOT SET' => 'shell', default => $provider }
if $real_provider == 'shell' {
$real_command = "set -o pipefail; $command"
} else {
warning('Non-shell command declared via mymodule::exec')
$real_command = $command
}
exec { $title:
command => $real_command,
provider => $real_provider,
creates => $creates ? { 'NOT SET' => undef, default => $creates },
cwd => $cwd ? { 'NOT SET' => undef, default => $cwd },
# ... all remaining regular parameters ...
}
}

Using puppet to install postgres without puppet-postgres

I am trying to install postgresql, set up a database and a user, but I am stuck at the setting up a database and use part. What I have so far is:
# Install postgres
class postgres::install {
package { [
'postgresql',
'postgresql-contrib',
]:
ensure => "installed",
}
}
But now how do I use this to create a user, database and grant all permissions on that database to that user?
You can do this a couple of ways, but the easiest way to do it repeatedly is with a define that calls a couple of execs:
Exec {
path => [
'/usr/local/sbin',
'/usr/local/bin',
'/usr/bin',
'/usr/sbin',
'/bin',
'/sbin',
]
}
define postgres::db_setup (
$dbname,
){
exec { "configure_db_${dbname}":
command => "pg command here using ${dbname}; touch success.txt"
creates => "db_${dbname}_success.txt"
}
}
define postgres::user_setup (
$dbuser,
$dbpassword,
$dbname,
){
exec { "configure_user_${dbuser}_on_${dbname}":
command => "pg command here using ${dbuser} on ${dbname} identified by ${dbpassword}; touch usersuccess.txt"
creates => "user_${dbuser}_success.txt"
}
Then when you call the defines:
postgres::db_setup { 'this_new_db':
dbname => 'mynewdbname'
}
postgres::db_user { 'this_new_db_user_on_dbname':
dbuser => 'mynewdbuser',
dbpassword => 'blahblah',
dbname => 'mynewdbname',
require => Postgres::Db_setup['this_new_db'],
}
This is a very dirty way to accomplish what you want by using dummy files to register when an exec has been completed. In my MySQL environment I use execs on scripts created with erb templates to allow more refined error checking.

Puppet: Passing parameters through classes

This is a follow on to my earlier question about parameterized classes. Following on that example a little further, I want to be able to pass running or stopped into the service, but when I add the service to a box, I don't use "include poodle::service", I use "include poodle" which does all of the other stuff Poodle requires to be installed.
So, can I pass the variable along to the service class like this:
# SITE.PP
node 'tweedle.example.com' {
include basicstuff
include poodle
}
node 'beetle.example.com' {
include basicstuff
class { 'poodle':
$ensure => 'stopped'
}
}
## POODLE MODULE, manifests/init.pp
class poodle ( $ensure = 'running' ) {
class {'poodle::install': }
class {'poodle::config': }
class {'poodle::service':
ensure => $ensure
}
Class ['poodle::install'] -> Class ['poodle::config'] ~> Class ['poodle::service']
}
...
class poodle::service ( $ensure ) {
service {'poodle':
ensure => $ensure,
enable => true,
restart => "/etc/init.d/poodle stop && sleep 5 && /etc/init.d/poodle start",
subscribe => File['/opt/poodle/poodle.py'],
}
}
Or should I put the parameter directly on the service class and the explicitly call both the Poodle class and Poodle's service class like this:
# SITE.PP
node 'tweedle.example.com' {
include basicstuff
include poodle
}
node 'beetle.example.com' {
include basicstuff
include poodle
class { 'poodle::service':
$ensure => 'stopped'
}
}
## POODLE MODULE, manifests/init.pp
class poodle {
class {'poodle::install': }
class {'poodle::config': }
class {'poodle::service':
ensure => $ensure
}
Class ['poodle::install'] -> Class ['poodle::config'] ~> Class ['poodle::service']
}
...
class poodle::service ( $ensure = 'running') {
service {'poodle':
ensure => $ensure,
enable => true,
restart => "/etc/init.d/poodle stop && sleep 5 && /etc/init.d/poodle start",
subscribe => File['/opt/poodle/poodle.py'],
}
}
Or is adding the parameter to the service class and including ONLY that enough, because the service class has dependencies, like this:
# SITE.PP
node 'tweedle.example.com' {
include basicstuff
include poodle
}
node 'beetle.example.com' {
include basicstuff
class { 'poodle::service':
$ensure => 'stopped'
}
}
## POODLE MODULE, manifests/init.pp
class poodle {
class {'poodle::install': }
class {'poodle::config': }
class {'poodle::service':
ensure => $ensure
}
Class ['poodle::install'] -> Class ['poodle::config'] ~> Class ['poodle::service']
}
...
class poodle::service ( $ensure = 'running') {
service {'poodle':
ensure => $ensure,
enable => true,
restart => "/etc/init.d/poodle stop && sleep 5 && /etc/init.d/poodle start",
subscribe => File['/opt/poodle/poodle.py'],
}
}
What is the right course and best practice here? Thanks in advance!
Generally, you don't want people to have to understand the internal structure of your module to use it.
I certainly wouldn't require them to include both poodle and poodle:service.
Modules usually follow one of two structures:
Single entry point via init.pp for simple services with few/no params and no separate roles
(client/server) or "multiples" (like a database server could have multiple db's configured in
it via puppet)
Multiple entry points via subclasses and defined types that handle separate roles and
multiples
Based on what you've described, I would place the parameter in the main class and pass it through to the service subclass.
node 'beetle.example.com' {
class { 'poodle::service':
ensure => 'stopped'
}
}
works.
But I disagree saying "you don't want people to have to understand the internal structure of your module" in that point that you want the flexibility when creating vhosts to define what port, protocol, what backend - proxy + and what modules etc. should be used.
I don't see a way for my projects how to enable such flexibility by just writing include apache, nginx or such.