Conditional catalog compilation - puppet

I have two servers, for example app01.zone1.mydomain.com and app01.zone2.mydomain.com. I have a class app that the node classifier assigns to each host with hostname matching app*. The app class is something like the following:
class app inherits common {
include 'appm'
}
It just includes the appm module.
Now, the appm module got some code which would break in zone2. So, I modified the app class to the following.
class app inherits common {
if ($zone == 'zone1'){
include 'appm'
}
}
However, when the catalog is being compiled, the condition is ignored. Due to that, the compilation fails when the agent on app01.zone2.mydomain.com tries to sync.
Is there any way to make catalog compilation honour the condition ? Any other suggestion for the situation ?

You can use a conditional matching a regular expression for your case:
class app inherits common {
if $::fqdn =~ /^app(\d+)\.zone1\./ {
include 'appm'
}
}

Related

ArchUnit: how to test for imports of specific classes outside of current package?

To externalize UI strings we use the "Messages-class" approach as supported e.g. in Eclipse and other IDEs. This approach requires that in each package where one needs some UI strings there has to be a class "Messages" that offers a static method String getString(key) via which one obtains the actual String to display to the user. The Strings are internally accessed/fetched using Java's Resources mechanism for i18n.
Esp. after some refactoring - we again and again have accidental imports from a class Messages from a different package.
Thus I would like to create an archunit rule checking whether we only access classes called "Messages" from the very same package. I.e. each import of a class x.y.z.Messages is an error if the package x.y.z is not the same package as the current class (i.e. the class that contains the import)
I got as far as this:
#ArchTest
void preventReferencesToMessagesOutsideCurrentPackage(JavaClasses classes) {
ArchRule rule;
rule = ArchRuleDefinition.noClasses()
.should().accessClassesThat().haveNameMatching("Messages")
.???
;
rule.check(classes);
}
but now I got stuck at the ???.
How can one phrase a condition "and the referenced/imported class "Messages" is not in the same package as this class"?
I somehow got lost with all these archunit methods of which none seems to fit here nor lend itself to compose said condition. Probably I just can't see the forest for the many trees.
Any suggestion or guidance anyone?
You need to operate on instances of JavaAccess to validate the dependencies. JavaAccess provides information about the caller and the target such that you can validate the access dynamically depending on the package name of both classes.
DescribedPredicate<JavaAccess<?>> isForeignMessageClassPredicate =
new DescribedPredicate<JavaAccess<?>>("target is a foreign message class") {
#Override
public boolean apply(JavaAccess<?> access) {
JavaClass targetClass = access.getTarget().getOwner();
if ("Message".equals(targetClass.getSimpleName())) {
JavaClass callerClass = access.getOwner().getOwner();
return !targetClass.getPackageName().equals(callerClass.getPackageName());
}
return false;
}
};
ArchRule rule =
noClasses().should().accessTargetWhere(isForeignMessageClassPredicate);

Puppet manifest: Overriding default variables in Hash

I've been handed the code for a Puppet module which was written by someone else. I've been tasked with getting it working in an actual Puppet environment.
I'm struggling to override defaults in the module in the manifest file. Hopefully this is a syntax issue, and not a issue with the init class.
In init.pp:
class our_module(
# Defaults to be overridden in the manifest file
Hash $config = {
'id' => '38e18a',
'secret' => 'donttellanyone',
'path' => '/test/path'
}
){
# Logic here...
}
How can I override these attributes? I've tried the following which gives my an InvalidCredentialsException:
node 'my_node' {
class { 'our_module':
config => {
id => 'newid',
secret => 'newsecret',
path => '/newpath
}
}
I'm new to Puppet and still getting my head around the docs and the syntax.
Given class our_module as presented in the question, this variation on the node block is valid for declaring that class and customizing its config parameter:
node 'my_node' {
class { 'our_module':
config => {
id => 'newid',
secret => 'newsecret',
path => '/newpath'
}
}
}
Hopefully this is a syntax issue, and not a issue with the init class.
If what you're really using takes the same form as above, then I'm sorry to have to tell you that the problem is not with your class declaration. If your Puppet runs are successful for nodes that do not declare class our_module, then my conclusion would be that the issue is indeed with the class implementation.
I've tried the following which gives my an InvalidCredentialsException
I am disinclined to think that that arises during catalog building. I cannot completely rule out the possibility, but that sure looks like a Java exception, whereas the catalog builder is implemented mainly in Ruby. It could be coming from puppetserver, Puppet's Java-based server front end, but that would not depend on whether your manifests declare a particular class. My crystal ball suggests that the our_module implementation is Execing a Java program when it is applied to the client, and that it is that program that is throwing the exception.
Some of those possibilities could be related to bad class parameter data, but I don't see any reason to think that the issue arises from a syntax error.

In puppet, how to retrieve variables inside a class scope from a different parameterized class

In the scope of one class, I need to be able to access a variable from another class. The variable is passed as a parameter, e.g.
class parameterized_class (
$param1,
) {
...
}
and
class other_class () {
include parameterized_class
Class['parameterized_class'] -> Class['other_class']
$local_var = $parameterized_class::param1
}
With an example usage of:
node default {
class { 'parameterized_class':
param1 => 'somevalue',
}
class { 'other_class': }
}
The above example does not work, as I get an error that looks roughly like:
Must pass param1 to
Class[Parameterized_class] at
/path/to/modules/parameterized_class/manifests/init.pp:1
on node localhost
Obviously, include is trying to declare parameterized_class without passing any parameters. But from the docs, I can see that include allows for a class to have been already previously declared, and since I have the parameterized_class declaration as a dependency of other_class, I don't understand how I could be getting this error.
I'm using Puppet 3.4.3, the version available on Ubuntu 14.04 Trusty
How should I go about retrieving the value of the $param1 in parameterized_class from within other_class's scope? Is it not possible to use include on parameterized classes?
According to the Puppet documentation (https://docs.puppet.com/puppet/3.5/lang_classes.html#include-like-behavior) you cannot use include-like declarations with mandatory parameters. In your case, what you can do is just not bother with the include since you've already handled that by declaring it in your node definition. Also, because both are declared in your node definition you would want to order them there as well.
As a side note not providing default values is a bad practice as is using variables across modules.

Puppet: Declaring a class with inheritance

I currently have two classes that I created within /etc/puppet/modules/params/manifests/init.pp
class modulename ($variable_name = 'Any string') inherits modulename::params{
file { '/tmp/mytoplevelclass.sh' :
mode => '644',
ensure => 'present',
content => $variable_name
}
}
class modulename::params{
}
However, I am having an issue declaring these classes in /etc/puppet/manifests/site.pp. Currently, I have it written as
node default { #client
class { 'modulename':}
class { 'modulename::params':}
}
I know that this is incorrect because when I run puppet agent -t on the client I get an error stating
Could not find declared class modulename at /etc/puppet/manifests/site.pp
I have tried several different configurations and still am unsure on what to do.
Puppet determines the file in which it expects to find a class's definition based on the class's fully-qualified name. The docs go into it in some detail; in particular, you should review the Module Fundamentals. (I am guessing that you are on Puppet 3, but the details I am about to discuss are unchanged in Puppet 4.)
Supposing that /etc/puppet/modules is a directory in your modulepath, it is a fine place to install (or write) your modulename module, as indeed you indicate you are doing. If it is not in your module path, then you'll want either to move your module to a directory in the module path, or to add that directory to the module path. I assume that you will resolve any problem of this sort via the latter alternative, so that /etc/puppet/modules/modulename is a valid module directory.
Now, class 'modulename' is a bit special in that its name is also a module name; as such, it should be defined in /etc/puppet/modules/modulename/manifests/init.pp. Class modulename::params, on the other hand, should follow the normal pattern, being defined in /etc/puppet/modules/modulename/manifests/params.pp. I anticipate that Puppet will find the definitions if you put the definitions in the correct files.
Bonus advice:
Use include-like class declarations in your node blocks, not resource-like declarations
Your node blocks probably should not declare modulename::params at all

Changing class variable in node declaration in Puppet

I am trying to create a "template" for all my servers. I have 2 configurations. An NTP client (which is taken care of in the baseclass class. I want to create an override specific for the NTP servers by declaring something specific in the node declaration. Something like "baseclass::ntp:restrict => true,". Or alternatively, how would I change one of the already declared variable from baseclass::ntp?
Does anyone have any ideas host to do this?
This is what I have so far:
templates.pp
class baseclass {
include defaultusers
include sudoers
include issue
class { ntp:
ensure => running,
servers => ['ntpserver1.host.com',
'ntpserver2.host.com',],
autoupdate => false,
}
}
nodes.pp
node default {
include baseclass
}
node "ntpserver1.host.com" inherits default {
<some code here to declare new variable in baseclass::ntp>
<some code here to change existing variable, such as "ensure">
}
You have run smack into the problem with parameterized classes: they don't support overrides. They should, but due to various problems with the order in which things are initialized in Puppet, you can't override parameters to classes. Once you set them, you're done. This is different from defines, where overriding parameters works as you expect. There's an open bug about this that a bunch of us have voted up and are watching, but there appears to be little progress.
Given that, my recommendation would be to recast your parameterized ntp class as a define instead, because a define will work exactly as you want. Change the class to something like:
define ntp($servers, $autoupdate = false, $ensure = 'running') {
# ... put code from class here ...
}
and then change baseclass to:
ntp { $fqdn:
servers => [ 'ntpserver1.host.com',
'ntpserver2.host.com',],
}
You will have to change the class structure to add a new class, since you can't inherit from a class in a node, so change your node to:
node "ntpserver1.host.com" inherits default {
include hosts::ntpserver1
}
or however you want to name your per-host configuration classes. Then, in that class, you can do exactly what you expect to be able to do:
class hosts::ntpserver1 inherits baseclass {
Ntp["$fqdn"] { ensure => 'stopped' }
}
I know this seems like a huge runaround, particularly if you're used to doing a bunch of stuff inside nodes (which don't participate in the class inheritance tree). But without being able to override parameters to classes, there doesn't seem to be a good alternative. (We manage 500+ nodes and about 100 completely separate service definitions, with hundreds of modules and a huge amount of variety between hosts, including per-host overrides, using this method and it works extremely well.)
TL,DR summary: You can't override class parameters. Once you've passed a parameter to a class in Puppet, you're done. You can override define parameters. Therefore, anything you want to override is better written as a define than a class. However, remember that override hierarchies means that you have to put the core of your node definition in a class, since only classes can inherit from and override another class. Therefore, if you use overrides heavily, get into the habit of having your node definitions be trivial (just including a class that does all the work) so that your classes can inherit from base classes and override the parameters to defines.
I accepted rra's answer, but I found a solution that worked for me a little better. It's a slight hack, I suppose:
template.pp
class baseclass ($ntprestrict = 'false') {
include defaultusers
include sudoers
include issue
class { ntp:
ensure => running,
servers => ['ntpserver1.host.com',
'ntpserver2.host.com',],
autoupdate => false,
restrict => $ntprestrict,
}
}
nodes.pp
node "ntpserver1.host.com" {
class { baseclass: ntprestrict => 'true' }
}
node "client.host.com" {
class { baseclass: ntprestrict => 'false' }
}

Resources