I've created a puppet resource for interfaces. Most of the interface names on my switch are lowercase with the exception of Ethernet interfaces, so I munged the interface name to hopefully reduce errors in the manifest; e.g.:
manifest:
cisco_interface { 'Ethernet1/1': description => 'foo' }
type/cisco_interface.rb:
newparam(:name) do
munge { |value|
value.downcase
}
end
My provider code also downcases the interface names when I collect the list of interfaces with self.instances.
Okay, so this works great when I test with the manifest, but not so great with the puppet resource command which only works when I call it with the name already downcased:
switch# puppet resource cisco_interface 'Ethernet1/1'
cisco_interface { 'Ethernet1/1':
ensure => 'absent',
}
switch# puppet resource cisco_interface 'ethernet1/1'
cisco_interface { 'ethernet1/1':
ensure => 'present',
description => 'foo',
}
The puppet resource command name field seems to just be a simple filter so I think I'm stuck, but I thought I'd seen other resource types munging title values like this.
Is it possible to munge the title values in a way that works for both scenarios?
If not then I'm not sure whether it would be better to leave it case-sensitive since that is what users will see in the switch config, or to "help" them avoid errors in the manifest.
You are correct about what is happening here, puppet currently requires that the name passed into the command line exactly matches the name according to the type. It's buried a couple levels deep, but look at the find and resource_name methods of the RAL.
It doesn't seem to me like this would be a major change, so you might want to log a defect or make the change yourself!
Related
is it possible to create a system group from hiera?
I know how to create a system group in the manifest via class, but I have failed to move that to hiera
Any example of creating a systemgroup "foo" with gid "1000" in hiera would be highly appreciated.
Thanks
Hiera is a data service. It can provide data about system groups, or about any kind of resource at all, but you need at least a little bit of manifest code somewhere to make a resource declaration out of that. For example, this pushes all the details out of the manifest and into Hiera (or other manifest code):
class mymodule::groups(Hash[String, Hash] $groupdata) {
$groupdata.each |$gname, $params| {
group { $gname: * => $params }
}
}
Hiera data feeding that class might look something like this:
mymodule::groups::groupdata:
group1:
system: true
group2:
gid: 42
system: true
group3:
ensure: absent
The value for $groupdata is, as declared by the class, a Hash of Hashes. The keys are group names, and the values are hashes of property names and values for the built-in Group resource type.
There are many other ways that one could accomplish this, with different advantages and disadvantages. I present this one because it is among the simplest.
I have the following Puppet resource.
tidy {
'beat_lock':
age => '8h',
path => '/var/lib/beat/',
alias => 'beat_lock',
matches => 'run.lock',
type => 'mtime'
}
I am getting an error stating the following:
Error: Failed to apply catalog: Parameter matches failed on Tidy[filebeat_lock]: Tidy can't use matches with recurse 0, false, or undef
The entity I want to cleanup is a file not a directory. So, why is the error showing up?
The entity I want to cleanup is a file not a directory. So, why is the error showing up?
You're telling Puppet that the entity you want to clean up is the directory /var/lib/beat. That's what the path parameter designates if you specify it, or what the the resource title designates if you don't explicitly specify the path parameter. At the same time, you have not provided a value for the recurse parameter, so the resource defaults to non-recursive, as if you had specified recurse => false. It doesn't make sense to use matches in this context, where you've already specified exactly which file is to be managed.
There is a variety of ways to spell it, but the simplest way to express what you seem actually to want would be this:
tidy { '/var/lib/beat/run.lock':
age => '8h',
type => 'mtime'
}
If you prefer to be able to refer to this resource elsewhere as Tidy['beat_lock'] then you might instead say
tidy { 'beat_lock':
path => '/var/lib/beat/run.lock',
age => '8h',
type => 'mtime'
}
I don't see much reason to introduce an alias, however, and you certainly don't need one that's the same as the resource title. I don't have any aliases declared anywhere in my own manifest set, and I don't recommend their use.
I'm trying to set up a Puppet cron job with the following structure:
file { '/usr/local/sbin/file.py':
mode => '0755',
source => 'puppet:///modules/file.py',
require => File['/usr/local/sbin']
}
cron { "cronjob":
require => "ALL_THE_FILES_ABOVE"
command => "...command_to_run_script..."
minute => '*/1'
}
All of the above is in one file run_script.pp. I'm wondering how I can code the require => "ALL_THE_FILES_ABOVE" part.
Thanks!
Based on the information provided in your question, I am going to make the assumption that the contents of run_script.pp is many file resources and the listed cron resource. You state that you want the cron resource there to require all of the file resources in that class. Based on this, here is a clean and efficient solution.
There are a few complicated/advanced ways to arrive at a clean and efficient solution, but the easiest to understand is to use a resource default: https://puppet.com/docs/puppet/5.3/lang_defaults.html
With this, we can establish attribute/value pair defaults for all file resources contained in that scope. This would make it easier to use the before metaparameter on the file resources instead: https://puppet.com/docs/puppet/5.3/metaparameter.html#before
This simplifies the solution to a one-liner in your class:
File { before => Cron['cronjob'] }
Note there will be a caveat to this method, which is that if you are declaring, requiring, or containing a class within this manifest, then this default could be expanded to that "area of effect" and cause a circular dependency. In that case, you should use a per-expression resource default attribute: https://puppet.com/docs/puppet/5.3/lang_resources_advanced.html#per-expression-default-attributes
You can use a multiple require
file{'path/foo':}
file{'path/bar':}
file{'~/foobar':
require => [ File['path/foo'], File['path/bar'] ]
}
or you can use the ordering arrow
-> (ordering arrow; a hyphen and a greater-than sign) — Applies the resource on the left before the resource on the right.
file{'path/foo':} ->
file{'path/bar':} ->
file{'~/foobar':}
Here is more information about relationships and ordering in Puppet
Let us say that I have a case in which I need to apply only two files from a Puppet configuration on some production servers, without touching the rest of the configuration.
/opt/aservice/myfile/thekey.conf
/opt/myfile/thekey.salt
Let's also say that these are controlled by the following Puppet manifest:
#
# author: Nathan Basanese (nathan#basanese.com)
# date: 04/17/2048
#
class keyconfig ( $cluster ){
notify {"Deploying key config. files to $fqdn":}
file {'/opt/aservice/key/config/thekey.conf':
ensure => present,
mode => '0644',
owner => 'aservice-serv',
group => 'aservice-serv',
source => "puppet:///modules/keyconfig/$cluster/thekey.conf",
}
file {'/opt/aservice/key/config/thekey.salt':
ensure => present,
mode => '0644',
owner => 'aservice-serv',
group => 'aservice-serv',
source => "puppet:///modules/keyconfig/$cluster/thekey.salt",
}
}
How would I apply ONLY these two files to a given server from a Puppet Master?
Perhaps, in the puppet agent command that is run on the target server, could I specify a specific Puppet class to use?
I have used the puppet resource command before, but I'm not sure that would work, here.
Every resource is automatically tagged with the fully qualified name of the class or defined type in which it is declared, and with every namespace segment of the class or type name, among other tags. You can use those tags to filter the resources that will be applied during a given catalog run. In the particular example you describe, you could use
puppet agent --no-daemonize --onetime --tags keyconfig
to apply only the resources declared in class keyconfig (and in any other class declared by keyconfig, recursively, but in this case there are no such other classes).
You can also declare tags manually by using the tag metaparameter in your resource declarations. That can allow you to provide for identifying custom collections of resources. And speaking of collections, you can use tags in the selection predicates of resource collectors, too.
The only way to do that is to have that node contain only the class you are wanting to have applied. In your site.pp you would have the following where the 'myhost.dns' is your fqdn. and $mycluster would be replaced by your cluster string.
node 'myhost.dns' {
class { 'keyconfig':
cluster => $mycluster,
}
}
I have to write a policy for defining various Host groups, for a particular thing it should check set of parameters according to host group.
For example I have 2 different set of web cluster, On one cluster httpd.conf is kept under /usr/local/apache/httpd.conf and for another set it is kept under /etc/httpd/httpd.conf.
I have a policy to check file changes of these configuration but I want a way in which I can define for a particular host group where exactly it should check.
Any Hint, help would be very appreciable.
The general answer is that you define a class for each group, and assign the appropriate path onto a variable according to that. For example:
vars:
group1::
"httpd_conf" string => "/usr/local/apache/httpd.conf";
group2::
"httpd_conf" string => "/etc/httpd/httpd.conf";
Then you use $(httpd_conf) in the file operations, and it will have the correct value according to the group.
The potentially tricker part is how to define those classes. In this case it depends on your setup and your preferences. For example, you could define the classes by explicitly listing the hosts in each group:
classes:
"group1" or => { "host1", "host2", "host3" };
"group2" or => { "host4", "host5", "host6" };
Or by matching against hostname patterns:
classes:
"group1" expression => classmatch("grp1.*");
"group2" expression => classmatch("grp2.*");
There are other possibilities. For a full treatment, please check Defining classes for groups of hosts in Chapter 6 of my book "Learning CFEngine 3".