I have an each iteration in Puppet to install Perl module extensions:
$extensions_list = ["extension1",
"extension2",
]
$extensions_list.each |$extls| {
exec { $extls:
path => '/usr/local/bin/:/usr/bin/:/bin/',
command => "wget http://search.cpan.org/CPAN/authors/id/B/BP/BPS/extension1-1.00.tar.gz",
}
}
What I would like it to do as well is to take into account the version number, as in:
$extensions_list = ["extension1", "1.00",
"extension2", "2.00",
]
$extensions_list.each |$extls| {
exec { $extls:
path => '/usr/local/bin/:/usr/bin/:/bin/',
command => "wget http://search.cpan.org/CPAN/authors/id/B/BP/BPS/extension1-1.00.tar.gz",
}
}
So, I'd like it to be able to take the first two variables in the array to install the first extension and then the next two and install that and so on and so on as I add new extensions. That way I can just add the name and version number to my array and it will install them in turn.
I have an each iteration in Puppet to install Perl module extensions:
Well, no, not exactly. You have an each operator to declare an Exec resource corresponding to each element of your array. Among potentially important distinctions from what you said is that the operation is evaluated during catalog building, so no actual installations are taking place at that time.
So, I'd like it to be able to take the first two variables in the array to install the first extension and then the next two and install that and so on
You could use the slice() function to split the array into an array of two-element arrays, and iterate over that. Consider, however, how much more natural it would be to use a hash instead of an array as the underlying data structure. Example:
$extensions_hash = {"extension1" => "1.00",
"extension2" => "2.00",
}
$extensions_hash.each |$extls, $extv| {
exec { $extls:
path => '/usr/local/bin/:/usr/bin/:/bin/',
command => "wget http://search.cpan.org/CPAN/authors/id/B/BP/BPS/$extls-$extv.tar.gz",
}
}
Related
I am trying to read keys from a hiera json file into an array.
The json is as follows:
{
"network::interfaces": {
"eth0": {
"ip": "10.111.22.10"
},
"eth1": {
"ip": "10.111.22.11"
},
"eth2": {
"ip": "10.111.22.12"
}
}
}
In my Puppet code, I am doing this:
$network_interfaces = hiera_array('network::interfaces')
notice($network_interfaces)
Which results in the following:
Notice: Scope(Class[Role::Vagrant]): {eth0 => {ip => 10.111.22.10}, eth2 => {ip => 10.111.22.11}, eth3 => {ip => 10.111.22.12}}
But what I want are just the interfaces: [eth0, eth1, eth2]
Can someone let me know how to do this?
The difference between hiera_array() and plain hiera() has to do with what happens when the requested key (network::interfaces in your case) is present at multiple hierarchy levels. It has very little to do with what form you want the data in, and nothing to do with selecting bits and pieces of data structures. hiera_array() requests an "array-merge" lookup. The more modern lookup() function refers to this as the "unique" merge strategy.
It seems unlikely that an array-merge lookup is in fact what you want. In that case, the easiest thing to do is read the whole hash and extract the keys:
$network_interfaces = keys(hiera('network::interfaces'))
In Puppet 4 you'll need to use the keys() function provided by the puppetlabs/stdlib module. From Puppet 5 on, that function appears in core Puppet.
I am installing from github using puppet-vcsrepo. The code looks something like this:
class demo_class(
$my_repo = undef,
$my_tag = undef,
){
vcsrepo { "$my_repo",
path => "/home/user/$my_repo",
source => 'git#github.com:7yl4r/$my_repo.git',
ensure => latest,
provider => git,
}
# then declare resources specific to my_tag
}
This works just fine when called only once, but I am iterating over a list and installing dependencies so this resource sometimes gets declared twice. I think this is roughly equivalent to the code below.
class {"demo_class":
my_repo => test_repo,
my_tag => test_tag1,
}
class {"demo_class":
my_repo => test_repo,
my_tag => test_tag2,
}
Doing this yields a server-side "Duplicate declaration" error because vcsrepo is trying to map the the same path twice. However, this is exactly the behavior I want: for both resources declared by demo_class to require the same repo in the same location. This is so that I can declare one or more resources using demo_class and be sure the repo given by my_repo (which may be common to multiple my_tags) is there.
How can I modify this class so that I can call it twice without hitting an error?
I see the problem.
I reproduced the issue using this code:
define my_vcs_repo ($myRepo, $myTag) {
vcsrepo { "$myRepo-$myTag":
path => "/home/user/$myRepo",
source => "git#github.com:7yl4r/$myRepo.git",
revision => $myTag,
ensure => latest,
provider => git,
}
}
$data = [
{
myRepo => testRepo,
myTag => testTag1,
},
{
myRepo => testRepo,
myTag => testTag2,
},
]
$data.each |$i, $ref| {
$myRepo = $ref['myRepo']
$myTag = $ref['myTag']
my_vcs_repo { "$myRepo-$i":
myRepo => $myRepo,
myTag => $myTag,
}
}
That then results in:
Puppet::PreformattedError:
Evaluation Error: Error while evaluating a Resource Statement, Evaluation Error: Error while evaluating a Resource Statement, Cannot alias Vcsrepo[testRepo-testTag2] to ["/home/user/testRepo"] at /
Users/alexharvey/git/modules/foo/spec/fixtures/modules/foo/manifests/init.pp:3; resource ["Vcsrepo", "/home/user/testRepo"] already declared at /Users/alexharvey/git/modules/foo/spec/fixtures/modules/foo/
manifests/init.pp:3 at /Users/alexharvey/git/modules/foo/spec/fixtures/modules/foo/manifests/init.pp:3:5 at /Users/alexharvey/git/modules/foo/spec/fixtures/modules/foo/manifests/init.pp:26 on node alexs-macbook-pro.local
The problem is that you are asking Puppet to clone the same Git module to a directory but with two different tags checked out. That does not make sense.
The fix is that you need to specify a unique path in the vcsrepo path attribute, e.g.:
vcsrepo { "$myRepo-$myTag":
path => "/home/user/$myRepo-$myTag",
source => "git#github.com:7yl4r/$myRepo.git",
revision => 'production',
ensure => latest,
provider => git,
}
By the way, I notice you are using camelCase for your variables. Don't do that. Aside from the fact that it is not idiomatic for Puppet, there are things that will break in some versions of Puppet/Rspec puppet that I have seen.
Use snake_case for your variable names and class parameter names.
Update
The question has been edited, and it is now a question about how to declare the same vcsrepo in more than one class.
In general, try to refactor so that you do not need to do this in the first place. In other words, just move it out of this class and put it somewhere that is only expected to be declared once.
If you cannot do this for some reason, then you can also use virtual resources, which will allow you to declare it in multiple classes that will be declared on the same node.
To do that, you just have to rewrite what you have there as:
#vcsrepo { $my_repo:
path => "/home/user/$my_repo",
source => "git#github.com:7yl4r/$my_repo.git",
ensure => latest,
provider => git,
}
realize Vcsrepo[$my_repo]
Keep in mind that you will not be able to declare the class demo_class twice on the same node either. You would need to turn it into a defined type, as I did above.
It is mentioned in the comments below that you can also use ensure_resource and ensure_resources; see docs in stdlib.
I am looking forward to use mathematical operations on the input received in Logstash, but unable to see any of such filter.
Input is as following:
{
"user_id": "User123",
"date": "2016 Jun 26 12:00:12",
"data": {
"doc_name": "mydocs.xls",
"doc_size": "8526587",
}
}
The "doc_size" field will have bytes, I would like to add a new field say "doc_size_mb" which will contain the size in MB's.
So I want a simple division operation here like:
doc_size_mb = doc_size/(1024*1024)
I could see a link which says Logstash has math filter, but this is not visible here .
The logstash-filter-math is not a core plugin but it is available here. You can follow the next steps in order or install it:
> git clone https://github.com/robin13/logstash-filter-math.git
> cd logstash-filter-math
> gem build
> $LS_HOME/bin/logstash-plugin install logstash-filter-math-0.2.gem
If you don't want to install a 3rd party plugin just for that, you can also easily achieve the same computation with a ruby filter:
filter {
ruby {
code => "event['data']['doc_size_mb'] = event['data']['doc_size'].to_i / (1024 * 1024)"
}
}
I tried using the above approach to multiply an existing field by a factor value and update the value of the existing field in the event by this new scaled value in Logstash 7.0.1, but it did not work as expected.
I modified it to use the Event API's set() and get() methods which worked out for me.
Initial approach (did not work) -
filter {
ruby {
code => "event['data']['myField'] = event['data']['myField'].to_i * 0.25"
}
}
Working solution -
filter {
ruby {
code => "event.set('myField',event.get('myField')* 0.25)
}
}
The math filter or ruby are options for the general case of doing math in logstash, but for this specific use-case (converting MB) there is the bytes filter.
Using Puppet 3
Testing using rspec-puppet
Iterating over an array of hashes using a Defined Type
Getting an Error, telling me that my parameter (which defaults to the value of $title) cannot be accessed the way I am because it is not an Array or Hash
I'm using old-style iteration in a puppet module, creating a defined type to iterate over an array of hashes. I'm trying to write a test for this define in rspec-puppet, attempting to assign a hash to the :title using let(). The $title is then supposed to be set to my variable called $daemon, yet my tests keep throwing errors saying that $daemon is not a hash or array.
Here's how I'm creating my defined type:
define my_module::daemon_install ($daemon = $title) {
package {"${daemon['package_name']}":
ensure => "${daemon['package_version']}",
}
file {"${some_fact}/${daemon['binary']}.conf":
ensure => file,
content => "blah"
notify => Service["${daemon['name']}"],
}
service {"${daemon['name']}":
ensure => running,
enable => true,
}
}
And here's how I'm trying to set the title:
describe 'my_module::daemon_install' do
context 'with foo' do
let(:title) {
{
"name" => "foo",
"package_name" => "bar",
"package_version" => "1.0.1",
"binary" => "food",
}
}
# ...
end
end
And here's the error:
daemon is not a hash or array when accessing it with package_version
I'm actually abit new to using defined types for iteration, and very new at rspec-puppet, so I'm not sure if I'm missing something obvious here or not.
But why is it only complaining about package_version and not package_name? And more importantly: why is it not a hash, when (I believe) I'm setting it to a hash correctly in the spec file.
I should mention that another test, of a class which uses this defined type, completes successfully. So it seems related to how I'm trying to set the title when directly testing the define, if I were to guess.
Rspec always converts title into String.
Use $name in define() instead of $title and add the following into tests:
let :title do
{ ... }
end
let :params do
{ :name => title }
end
Please note$name should be equal of $title.
So I am using the https://forge.puppetlabs.com/pdxcat/nrpe module to try to figure out automation of NRPE across hosts.
One of the available usages is
nrpe::command {
'check_users':
ensure => present,
command => 'check_users -w 5 -c 10';
}
Is there anyway to make a "group" of these commands and have them called on specific nodes?
For example:
you have 5 different nrpe:command each defining a different check, and then call those specific checks?
I am basically trying to figure out if I could group certain checks/commands together instead of setting up a ton of text in the main sites.pp file. This would also allow for customized templates/configurations across numerous nodes.
Thanks!
EDIT:
This is the command and what it's supposed to do when called on with the 'check_users' portion. If I could have a class with a set of "nrpe:command" and just call on that class THROUGH the module, it should work. Sorry, though. Still new at puppet. Thanks again.
define nrpe::command (
$command,
$ensure = present,
$include_dir = $nrpe::params::nrpe_include_dir,
$libdir = $nrpe::params::libdir,
$package_name = $nrpe::params::nrpe_packages,
$service_name = $nrpe::params::nrpe_service,
$file_group = $nrpe::params::nrpe_files_group,
) {
file { "${include_dir}/${title}.cfg":
ensure => $ensure,
content => template('nrpe/command.cfg.erb'),
owner => root,
group => $file_group,
mode => '0644',
require => Package[$package_name],
notify => Service[$service_name],
}
}
What version are you talking about? In puppet latest versions, inheritance is deprecated, then you shouldn't use it.
The easiest way would be to use "baselines".
Assuming you are using a manifests directory (manifest = $confdir/manifests inside your puppet.conf), simply create a $confdir/manifests/minimal.pp (or $confdir/manifests/nrpe_config.pp or whatever class name you want to use) with the content below:
class minimal {
nrpe::command { 'check_users':
ensure => present,
command => 'check_users -w 5 -c 10',
}
}
Then just call this class inside your node definitions (let's say in $confdir/manifests/my_node.pp) :
node 'my_node.foo.bar' {
include minimal
}