Talk:Puppet Hiera

From Wikitech

How to associate node and role

In most cases, we want a set of servers to have very similar configuration, which is in most cases a 1:1 correspondence with the role class that is included in the node itself; but this is not always the case. So the solution is to have some "label" applied to the server, and then use it in looking up variables in hiera.

How we do this today

Right now, you would probably want to do it like this:

site.pp

node /^mc10[0-9][0-9]\.eqiad\.wmnet$/ {
    include role::foo
}

hieradata/regex.yaml

foocluster:
  __regex: !ruby/regex /^mc10[0-9][0-9]\.eqiad\.wmnet$/
  mainrole: foo_runner

hieradata/mainrole/foo_runner.yaml

foo::queue_len: 100
foo::threads: 8
admin::groups:
  - "oompah_loompahs"
  - "apache"
...

Which, while pretty organized, has the non-secondary disadvantage of asking us to replicate regexes twice.

The simplest alternative

The simplest and most obvious alternative would be to have a node-scope variable to use in every stanza to define the role we're applying:

site.pp

node /^mc10[0-9][0-9]\.eqiad\.wmnet$/ {
    $mainrole = "foo_runner"
    include role::foo
}

hieradata/mainrole/foo_runner.yaml

foo::queue_len: 100
foo::threads: 8
admin::groups:
  - "oompah_loompahs"
  - "apache"
...

The drawback of this solution is that anything evaluated before the node scope is entered will not be correctly affected by this. Also, it makes sites.pp ugly (but this is a personal taste of mine), and still forces us to declare a relationship that should be more relative to the applied role than to the nodes. Subgroup-specific settings could still be defined in one of the two preceding ways.

Another idea

We can make the role/node relationship unique; this will be ok in 99.9% of the cases, as long as it can be manually overridden. The main advantage of this is that we tie functionality to the role class, and not to the node group. We can also declare multiple roles, and we'll have a dedicated hiera backend for this

So we would have:

manifests/role/foo.pp

class role::foo {

    # All the code that usually is in the role class.
}

manifests/site.pp

node /^mc10[0-9][0-9]\.eqiad\.wmnet$/ {
    role foo
}

hieradata/role/foo.yaml

foo::queue_len: 100
foo::threads: 8
admin::groups:
  - "oompah_loompahs"
  - "apache"
...

which could be overridden in hieradata/role/eqiad/foo.yaml.

This has some slight caveats I can think of:

  • If more than one role is defined in a node def, all the hiera lookups on the roles must be identical, or an error will be thrown
  • Things that depend on this declared in the top scope (and not in the node scope) will not be able to access this.