2

Basically, I find myself making the same long class declaration every time:

node 'gluster3redis097.myservice.com' {
    class { 'redis' :
        class {'invoke' : }
        class {'users' : }
        class {'redis' :

        package_ensure        => '3.0.5',

        #extra_config_file    => '/etc/redis.d/redis-gluster3-master.conf',
        daemonize             => 'yes',
        pid_file              => '/var/run/redis.pid',
        log_level             => 'notice',
        log_file              => '/var/log/redis/redis.log',
        #save_db_to_disk       => false,
        workdir               => './',
        bind                  => $::ipaddress,
        slaveof                    => "${$gluster3redis_master_ips[37]}:6379",
        slave_serve_stale_data => true,
        # 2015.12.01  nathan  Do not allow inadvertent writes to the slave
        slave_read_only        => true,
        repl-diskless-sync-delay => '5',
        repl-ping-slave-period => '10',
... and so on ... 
... and so forth ...

Let us suppose, for this cluster, every FIFTH node has a separate master.

So, guess the only part that changes?

slaveof                    => "${$gluster3redis_master_ips[37]}:6379",

There has to be a better way.
-- Pocahontas (1995)1

According to https://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html#multiple-names, it's a bad idea to use the Puppet inherits keyword.

Plus, to my dismay, in https://docs.puppetlabs.com/puppet/latest/reference/lang_node_definitions.html#aside-best-practices , they describe the following best practices:

Aside: Best Practices

Although node statements can contain almost any Puppet code, we recommend that you only use them to set variables and declare classes. Avoid using resource declarations, collectors, conditional statements, chaining relationships, and functions in them; all of these belong in classes or defined types. This will make it easier to switch between node definitions and an ENC.2

Could I define a custom type?

I read through How to pass node specific information to class in puppet? , but I'm not sure he's asking the same thing that I am, and although I'm perfectly willing to learn how to define types, I'm not familiar with them enough to decide whether to go that route.

How the blazes do I avoid repeating myself with every Puppet Node definition like this for this Redis cluster?

I would welcome even a very generic answer that I could apply to my particular case, which I have also generalized.

UPDATE: Applying a common configuration using Hiera by a common.yaml file for this set of environments seems to have worked. I will elaborate further in an answer, if Dan Bowling does not volunteer one.

Community
  • 1
  • 1
Nathan Basanese
  • 8,475
  • 10
  • 37
  • 66
  • // , Let me know if this question is possible to answer, even. If Puppet Types are usually the best way to go for repeated `node` class declarations, then just add a quick comment and I can put the question on hold while I try that. – Nathan Basanese Dec 04 '15 at 09:45
  • 1
    Have you looked into using Hiera rather than declaring this on the node? You could then just set reasonable defaults in common.yaml, then have `"node/%{::hostname}"` set the one line that is unique per host. – Dan Bowling Jan 13 '16 at 23:54
  • // , Excellent idea! Someone wiser than I on our team recommended using Hiera. I think using Hiera would make this a lot more readable. We actually have 3 or 4 settings unique to each host. I take it that "then have `"node/%{::hostname}"` set the one line that is unique per host." in your comment means that we'd also use Hiera to set those items unique to each host, right? – Nathan Basanese Jan 14 '16 at 00:27
  • I've tried to give you a fuller answer. Leave a comment if you need more info and I'll update it. – Dan Bowling Jan 15 '16 at 22:58

1 Answers1

2

Here's a more flushed out answer for the comment I initially placed:

Any time you find yourself re-declaring settings as class parameters, Hiera should be considered. From the docs:

Hiera is a key/value lookup tool for configuration data, built to make Puppet better and let you set node-specific data without repeating yourself.

Your first step is to identify a hierarchy, since Hiera will use that hierarchy to look up an appropriate value for the requested key. In your example, a simple hierarchy is all that is needed. Here's an example hiera.yaml configuration file:

:backends:
  - yaml

:hierarchy:
  - "node/%{::hostname}"
  - "common"

:yaml:
  :datadir: '/your/hiera/data/directory'

:merge_behavior: deeper    

About the above config:

  1. Hiera will look in /your/hiera/data/directory/node/nodehostname.yaml for a value first. This is where you can define per-host configurations.
  2. For all other values, Hiera will revert to the default common.yaml in /your/hiera/data/directory/node/common.yaml

So, your common.yaml might look like this:

redis::package_ensure: '3.0.5'
redis::pid_file: '/var/run/redis.pid'

And you will have node{1,2} with this /your/hiera/data/directory/node/node{1,2}.yaml:

redis::slaveof: 'your redis master value'

And node{3,4} would have this /your/hiera/data/directory/node/node{3,4}.yaml:

redis::slaveof: 'your other redis master value'

The :merge_behavior: deeper in hiera.yaml is useful if you want to merge settings at different hierarchy levels or combine complex hashes into single values. For more info, see Hiera Lookup Types.

Dan Bowling
  • 1,205
  • 1
  • 15
  • 41