Search code examples
puppet

Using puppet lookup function to dynamically retrieve a server role per datacenter,zone,network tenant and environment


I'm writing a custom Puppet 7 profile for a master-slave type application, which needs to dynamically retrieve the master server hostname in the slave server configuration per data center, zone, network tenant and environment.I have the following template variables defined in my Puppet 7 environment:

<%= $facts[puppet_datacenter] %>
<%= $facts[puppet_zone] %>
<%= $facts[puppet_tenant] %>
<%= $facts[puppet_department] %>
<%= $facts[puppet_role] %>
<%= $facts[puppet_environment] %>
<%= $facts[location_id] %>

I need to dynamically retrieve the master server hostname per data center, zone, network tenant and environment so that I can join the slaves in the application cluster. Can anyone give me an example how this can be achieved?

I tried the following things:

  1. printing the facts on the command-line using facter -p works nicely
  2. looked into the documentation - using lookup,exec or if elseif are promising solutions, but I could not find extended code samples that give an idea how this can be done without spending 2-3 days on each method to solve it.

Solution

  • I need to dynamically retrieve the master server hostname per data center, zone, network tenant and environment

    One of these things is not like the others. The Puppet environment is a property primarily of your Puppet infrastructure, whereas the rest are properties primarily of the machines under management. This is important at least because

    • Puppet knows each node's environment already (supposing that you have a Puppet site up and running at all).
    • To the extent that Hiera is involved, you get data divided on a per-environment basis as a built-in feature.

    The other data need to be provided by some custom mechanism, which in your case is apparently a set of custom facts. That's fine. So the question now is how do you use those data to configure your slave nodes appropriately.

    To some extent, it depends on just how dynamic you want to be. There are lots of alternatives, but the two that seem most promising are

    1. Put the server hostname data into your Hiera data source. There are several variations on how that could be done, but the most idiomatic would be to create a hierarchy level for each combination of (center, zone, tenant) triple in each environment-level Hiera config. In the data for each such combination, record the appropriate server hostname. That will make it accessible in your manifests either via automatic data binding to a class parameter or via explicit use of lookup(), with all the details of matching nodes to center, zone, tenant, and environment handled behind the scenes.

    OR

    1. Have the servers export appropriate resources for the slaves to collect and use. The most natural way to do that would be to create a defined type encompassing the configuration details that the slaves must apply (at least those that depend on details of the master server), and have the class by which you manage the application details for the master server export an instance of that resource for the matched slaves to collect and apply.

    Option (1) requires you to explicitly track which is the master server for each group, and to keep your Hiera data up to date with respect to that. Option (2) will allow the slaves to discover the appropriate master more dynamically, without the mapping being managed explicitly, but it's a little more magic.

    Can anyone give me an example how this can be achieved?

    There are lots of examples available of setting up Hiera hierarchy levels based on fact values, of relying on Hiera for automatic data binding, and of looking up Hiera data explicitly, both here at SO and elsewhere. There are also plenty of examples of exported resource usage, with the most canonical examples being for managing /etc/hosts files.

    But requests for external resources are off topic here, and I'm stopping short of writing bespoke examples for this answer -- it is too broad of an ask, and this answer is already long. If you have trouble with implementing one or the other of those approaches, then a new question specific to that struggle could be on topic here.