Puppet - How to use $facts['name'] in notify {} - puppet

Question
How I can use $facts['fact name'] in notify?
Issue
The code below is OK.
$virt = $facts['virtual']
notify { "I'm using a value !${virt}! ": }
Notice: I'm using a value !vmware!
However, the code below shows (it looks) all the facts.
notify { "I'm using a value $facts['virtual'] ": }
Notice: I'm using a value {architecture => amd64, augeas => {version => 1.4.0}, augeasversion => 1.4.0, bios_release_date => 09/30/2014, bios_vendor => Phoenix Technologies LTD, bios_version => 6.00, blockdevice_fd0_size => 0, blockdevice_sda_model => Virtual disk, blockdevice_sda_size => 107374182400, blockdevice_sda_vendor => VMware, blockdevice_sdb_model => Virtual disk, blockdevice_sdb_size => 536870912000, blockdevice_sdb_vendor => VMware, blockdevice_sr0_model => VMware IDE CDR10, blockdevice_sr0_size => 1073741312, blockdevice_sr0_vendor => NECVMWar, blockdevices => fd0,sda,sdb,sr0, boardmanufacturer => Intel Corporation, boardproductname => 440BX Desktop Reference Platform, chassisassettag => No A ...... (a lot)
Kindly help oo get the same result as in the first, but not using ${::virtual} but using $facts['virtual'].

You do it like this:
notify { "I'm using a value ${facts['virtual']}": }

Related

What is the correct way to map and translate cookies in logstash?

My input is a log from IIS server with cookies included. I want my output (elasticsearch) to have a field like this:
"cookies": {
"cookie_name": "cookie_value"
}
Also for some cookies I want their values to be replaced with some other values from a dictionary.
Basically, I think the following filter config solves my problem:
kv {
source => "cookie"
target => "cookies"
trim => ";"
include_keys => [ "cookie_name1","cookie_name2" ]
}
translate {
field => "cookies.cookie_name1"
destination => "cookies.cookie_name1"
dictionary_path => "/etc/logstash/dict.yaml"
override => "true"
fallback => "%{cookies.cookie_name1}"
}
The problem is that I don't know if it’s the right way to do this, and whether it will work at all (especially the cookies.cookie_name part).
The correct way to do this is:
kv {
source => "cookie"
target => "cookies"
field_split => ";+"
include_keys => [ "cookie_name1","cookie_name2" ]
}
translate {
field => "[cookies][cookie_name1]"
destination => "[cookies][cookie_name1]"
dictionary_path => "/etc/logstash/dict.yaml"
override => "true"
fallback => "%{[cookies][cookie_name1]}"
}
https://www.elastic.co/guide/en/logstash/current/event-dependent-configuration.html#logstash-config-field-references
https://www.elastic.co/guide/en/logstash/7.4/plugins-filters-kv.html
https://www.elastic.co/guide/en/logstash/7.4/plugins-filters-translate.html

Adding custom server options with puppetlabs mysql module

I have a puppet manifest that contains this phrase (my question is about the production block at the end), used to set up mysql configuration files:
class web_mysql_server {
include web_mysql::packages
include web_mysql::mysql_server
}
class web_mysql::packages {
Package { ensure => installed }
package { 'libmysqlclient-dev': }
}
class web_mysql::mysql_server {
# Qualified keys (dot notation: web_mysql_server.mysql_database) isn't available
# until hiera 2.0.
$mysql_config = hiera('web_mysql_server')
# https://forge.puppetlabs.com/puppetlabs/mysql
class { '::mysql::server':
root_password => '...',
remove_default_accounts => true,
override_options => {
# The data in this block gets written to /etc/mysql/my.cnf.
'mysqld' => {
max_connections => '1024', # No good reason but parroting others.
key_buffer_size => '512M', # No good reason but parroting others.
},
'production' => {
adaptor => 'mysql2',
database => $mysql_config['mysql_database'],
user => $mysql_config['mysql_username'],
password => $mysql_config['mysql_password'],
host => '0.0.0.0',
encoding => 'UTF8',
},
But sometimes I'd maybe like the database to be a staging database, and so it's a bit confusing to call it production. No problem, I've recently learned about hiera, it's my hammer for all nails today:
$mysql_config['mysql_name'] => {
adaptor => 'mysql2',
database => $mysql_config['mysql_database'],
user => $mysql_config['mysql_username'],
password => $mysql_config['mysql_password'],
host => '0.0.0.0',
encoding => 'UTF8',
},
No, that doesn't work, though the error ("syntax error at line (...with '=>'...), expected '}'") isn't terribly revealing.
("Key" might be the wrong word. Please correct me. I'm a bit new to puppet. And that itself may be why I've not been able to answer this question by googling and reading.)
Thanks for any pointers.
Update: I see now that the mysql module provides an option to add section to the config file out of the box. Here is how it should be used according to the documentation:
$override_options = {
$mysql_config['mysql_name'] => {
adaptor => 'mysql2',
database => $mysql_config['mysql_database']
# ...
}
}
class { '::mysql::server':
root_password => 'strongpassword',
remove_default_accounts => true,
override_options => $override_options,
}
Or you can save some code if you put the mysql_name value under a different hiera key:
$override_options = {
hiera('mysql_name') => hiera('web_mysql_server')
}
Original answer:
If your actual intention is just to create a configuration file, the best way is using templates in erb syntax.
Here is an example. First, you put a my.cnf.erb file to the templates directory of your module (e.g. modules/web_mysql/templates):
[<%= #mysql_config['mysql_name'] %>]
adaptor = mysql2
database = <%= #mysql_config['mysql_database'] %>
user = <%= #mysql_config['mysql_username'] %>
password = <%= #mysql_config['mysql_password'] %>
host = 0.0.0.0
encoding = UTF8
You can use this template in your web_mysql::mysql_server class to create the config file:
class web_mysql::mysql_server {
# ...
$mysql_config = hiera('web_mysql_server')
file { '/etc/mysql/my.cnf':
ensure => 'present',
content => template('web_mysql/my.cnf.erb'),
}
}
The way you're using web_mysql::mysql_server indicates that the class has a parameter called production. If that is the case you have to use that name when you use the class. Instead, why not just call the parameter mysql or client, since it seems to be the client configuration parameter?
Answer to original question:
Neither version of your manifest is valid Puppet. For example, putting this in my manifest:
'production' => {
adaptor => 'mysql2',
}
and running puppet apply --noop --modulepath modules manifests/host.pp results in:
Error: Could not parse for environment production: Syntax error at '=>' at [...]/host.pp:1:14 on node hostname
Did you mean to say something like this?
$database_configuration = {
adaptor => 'mysql2',
database => $mysql_config['mysql_database'],
user => $mysql_config['mysql_username'],
password => $mysql_config['mysql_password'],
host => '0.0.0.0',
encoding => 'UTF8',
}

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.

Puppet - Pass hash as class argument(s)

Trying to do something like this:
# nodes.pp
node 'dev-a-1.sn1.vpc1.example.com' inherits project_j1n_sn1_vpc1_dev {
class { 'custom::core':
overrides => {
'openssh' => {'settings' => {'external_access' => 'true'}}, # Allow direct mounting for dev
'rsyslog' => {'settings' => {'role' => 'node', 'filters' => {'php' => {'target' => 'remote'}, 'mail' => {'target' => 'remote'}}}}
}
}
}
# custom::core
class custom::core($overrides = {}) {
if (has_key($overrides, 'openssh')) {
$settings = $overrides['openssh']['settings']
# Doesn't work
create_resources('openssh', $settings)
# Doesn't work
class { 'openssh': $settings }
}
}
Is it possible to call a class and pass a hash as the arguments?
Puppet/Puppetmaster v2.7.26-1 (Centos 6.7)
There is a way in Puppet 4+.
class { 'ssh':
* => $settings
}
Learn all about it on roidelapluie's blog.
A co-worker of mine had come up with a good solution to something similar in the old 2+ days of puppet. Utilized create_resources for this.
http://www.followski.com/quick-note-how-to-use-create_resources-to-initialize-a-class-in-puppet/
your code can look something like this:
nodes.pp
node 'dev-a-1.sn1.vpc1.example.com' inherits project_j1n_sn1_vpc1_dev {
class { 'custom::core':
overrides => {
'openssh' => {'settings' => {'external_access' => 'true'}}, # Allow direct mounting for dev
'rsyslog' => {'settings' => {'role' => 'node', 'filters' => {'php' => {'target' => 'remote'}, 'mail' => {'target' => 'remote'}}}}
}
}
}
custom::core
class custom::core($overrides = {}) {
if (has_key($overrides, 'openssh')) {
$settings = $overrides['openssh']['settings']
create_resources('class', { 'openssh' => $settings })
}
}
You will notice that in the example linked above it looks like create_resources('class', $params), but that assuming you have a hash with a key being the class name (ie openssh) and its value being the params to set. The example I state above essentially does the same thing.
Your node definition can also be look like this:
node 'dev-a-1.sn1.vpc1.example.com' inherits project_j1n_sn1_vpc1_dev {
class { 'custom::core':
overrides => {
'openssh' => {'external_access' => 'true'}, # Allow direct mounting for dev
'rsyslog' => {'role' => 'node', 'filters' => {'php' => {'target' => 'remote'}, 'mail' => {'target' => 'remote'}}}
}
}
}
and your class something like this:
class custom::core($overrides = {}) {
if (has_key($overrides, 'openssh')) {
create_resources('class', {'openssh' => $overrides['openssh'])
}
if (has_key($overrides, 'rsyslog')) {
create_resources('class', {'rsyslog' => $overrides['rsyslog'])
}
}
I think you get the point by now.
We used this quite often a few years ago. You may want to consider moving towards an upgrade of your puppet infrastructure however.
Hope this helps, or at least points you in the right direction.

Apache Cassandra schema design

I have following setup:
Have CF items and CF keywords.
Each item have zero, one or more keywords, stored in columns.
Each keyword have one or more items, stored in columns.
It looks like this:
items {
dl { name => DELL6400, keyword:1 => computer, keyword:2 => DELL, keyword:3 => topseller }
hp { name => HP12345, keyword:1 => computer, keyword:2 => HP }
no { name => Nokia8210, keyword:1 => phone, keyword:2 => NOKIA }
}
// here I store keys of the items only,
// in reality I have denormalized most of items columns
keywords{
computer { webpage => www.domain.com/computer , item:dl => dl , item:hp => hp }
DELL { webpage => www.domain.com/dell , item:dl => dl }
topseller { webpage => www.domain.com/top , item:dl => dl }
HP { webpage => www.domain.com/hp , item:hp => hp }
NOKIA { webpage => www.domain.com/nokia , item:no => no }
phone { webpage => www.domain.com/phone , item:no => no }
}
when I add new item, I am adding "webpage" column in keywords if neccessary.
when I am removing an item, I am removing column "item:xx" as well
question is how to avoid "empty" keywords such if I remove nokia item "no":
keywords{
...
NOKIA { webpage => www.domain.com/nokia }
phone { webpage => www.domain.com/phone }
}
I can count slice item:*, but because of eventual consistency this will be probably wrong aproach.
You can add a CounterColumn (http://wiki.apache.org/cassandra/Counters) to keywords CF. Increment it when adding an item to the keyword, and decrement on removal:
keywords{
computer { webpage => www.domain.com/computer , count => 2 , item:dl => dl , item:hp => hp }
....
}
When reading a row with count == 0, just treat it as deleted. You shouldn't actually delete the 'webpage' column if you read the row with count == 0, since there might be concurrent add operation.
this is interesting, but I though about other way - to denormalize the "webpage" thing, e.g.:
[code]
keywords{
computer { webpage:dl => www.domain.com/computer , item:dl => dl ,
webpage:dl => www.domain.com/computer , item:hp => hp }
DELL { webpage:dl => www.domain.com/dell , item:dl => dl }
topseller { webpage:dl => www.domain.com/top , item:dl => dl }
HP { webpage:hp => www.domain.com/hp , item:hp => hp }
NOKIA { webpage:no => www.domain.com/nokia , item:no => no }
phone { webpage:no => www.domain.com/phone , item:no => no }
}
[/code]
in such case when i delete item:xx, i delete webpage:xx as well, and row is auto-removed (ghost) if there is no fields there. However I am still not sure if this is such a bright idea.

Resources