About | FAQ | Help
Ask Your Question

Is there a way to auto assign a role and environment to a node ?

asked 2018-01-02 10:57:34 -0500

JQ1982 gravatar image

updated 2018-01-09 13:31:00 -0500

DarylW gravatar image

Is there a way to assign a node on joining the puppet master a role and environment?

curl -k https://puppet.localdomain:8140/packages/current/install.bash | sudo bash -s main:certname=${hostname}.localdomain main:server=puppet.localdomain custom_attributes:challengePassword=${puppet_challenge_password}
edit retag flag offensive close merge delete

6 Answers

Sort by » oldest newest most voted

answered 2018-01-04 11:45:23 -0500

reidmv gravatar image

updated 2018-01-04 12:52:44 -0500

Role assignment based on pp_role can be accomplished by putting something like this in your site.pp:

node default {

  # Save the trusted pp_role to a shorter variable so it's easier to work with.
  $role = $trusted['extensions']['pp_role']

  case $role {
    default: {
      include $role
    undef, '': {
      fail("${trusted['certname']} does not have a pp_role trusted fact!")


The code here assumes all nodes must have a pp_role trusted fact. If some nodes don't have pp_role, you can modify the undef, '' case accordingly.

For centrally-defined environment assignment, the Puppet Enterprise node classifier or another ENC must be used. It is not possible to assign environment inside Puppet code (because the environment is what determines which code will be loaded).

Agent-side environment can be defined by passing a setting when running the install script. agent:environment=nonproduction, for example.

To assign environments automatically based on pp_environment, a Node Group structure such as the following can be used.

image description

The "Default environent" group should match all nodes, using a rule like this one:

name ~ .+

If nodes don't have a pp_environment trusted fact they will be placed into the environment dictated by this group. In the example, they will be placed into an environment called "disabled".

For each specific environment group (such as production or integration in the example), use a rule based on pp_environment. These are a few examples:

trusted.extensions.pp_environment = production
trusted.extensions.pp_environment = integration

You must have one node group per environment. (temporary environment assignment during development is what the "temp assignment" subgroups are for; but even testing nodes have a "home" environment, which is the value of their pp_environment trusted fact).

The "$env temp assignment" node groups must be set up if you want to be able to run puppet agent -t --environment=nondefault on your agents. These groups are what tell the classifier it's allowed to let agents choose their own environment.

The rules for these "$env temp assignment" groups should include the agent_specified_environment special fact. The rule in each of these groups may look like this.

agent_specified_environment ~ .+

For some limited documentation, see this page.

If you are using both of these patterns—site.pp for role assignment based on pp_role, and environment node groups for environment assignment based on pp_environment—you should need only to assign pp_role and pp_environment at agent install time to put nodes in roles and environments. This can be done with arguments to the install script.

curl -k https://puppet.localdomain:8140/packages/current/install.bash | sudo bash -s \
  main:certname=${hostname}.localdomain \
  customattributes:challengePassword=${puppetchallenge_password} \
  extension_requests:pp_role=${puppet_role} \
edit flag offensive delete link more



Awesome!!! thank you verify much.

JQ1982 gravatar imageJQ1982 ( 2018-01-04 13:37:53 -0500 )edit

answered 2018-01-04 16:22:42 -0500

greynolds gravatar image

Hum..... Have you considered applying your roles and envoronment during provisioning? This approach may resolve your concern? In short, when the nodes is built you will a role and an environment configured once the provisioning is complete.


edit flag offensive delete link more


There are many options as you can see to address your concerns with assigning roles and profiles automatically. I would look into using razor to define a policy to add your roles and profiles during provisioning, It will save you some time.

greynolds gravatar imagegreynolds ( 2018-01-17 13:29:41 -0500 )edit

adding this to the node classifier @enc["classes"]["role"] = Hash.new @enc["classes"]["profile"] = Hash.new

greynolds gravatar imagegreynolds ( 2018-01-17 13:43:55 -0500 )edit

Can help with the scaling of your roles and profiles. node 'role' { hiera_lookup('classes' == [ $environment.fqdn ]) } node 'profile' { hiera_lookup('classes' == [ $environment.fqdn ]) }

greynolds gravatar imagegreynolds ( 2018-01-17 13:46:48 -0500 )edit

Per Environment... hierarchy: - name: "Nodes" backend: yaml paths: - "nodes/%{::trusted.certname}" - "%{environment}/%{calling_modules}" - "%{environment}/%{calling_class}" - "%{environment}/%{role}" - "%{role}" - "%{role}/%{::profile}" - "%{profile}

greynolds gravatar imagegreynolds ( 2018-01-17 13:51:18 -0500 )edit

answered 2018-01-15 09:35:42 -0500

zippycup gravatar image

updated 2018-01-15 09:45:35 -0500

I would add this to site.pp As per link text use node keyword.

To make the code cleaner, create a directory 'nodes' under site.pp and add this code to site.pp

 import 'nodes/*.pp'

I do not like to set facter on the target server to determine its environment or role so we incorporation the environment and role in the name of the host. This way I can change the role of the server without going on the host and changing the facter.

example for assigning role apache:

hostname: dev-apache-1.useast1a.mydomain.net

set environment


# environment='dev'

if you had a heterogeneous environment aka crappy hostname convention. Yes, that is actual code from a previous gig.

if $environment == undef {

  if $fqdn =~ /-dev-/ or $fqdn =~ /^dev-/  {
    $environment = 'dev'
  elsif $fqdn =~ /-qal-/ or $fqdn =~ /-qa-/ or $fqdn =~ /^qal-/ {
    $environment = 'qal'
  elsif $fqdn =~ /stg-/ or $fqdn =~ /stag/ or $fqdn =~ /^stg-/ {
    $environment = 'stg'
  elsif $fqdn =~ /-prd-/ or $fqdn =~ /prod/ or $fqdn =~ /^prd-/ or $fqdn =~ /.prd./ {
    $environment = 'prd'
  else {
    $environment = 'dev'

set role


node /-apache-[0-9]/ {
  include role::apache
edit flag offensive delete link more

answered 2018-01-03 10:35:19 -0500

yes - there is a few ways to do this - could base role on a function of hostname - however unless you have a good hostname standard this would be difficult, alternatively use an ENC to define role - simplest way I have found is to have list of roles in a text file and add hosts to each line..

edit flag offensive delete link more


I do have a good naming convention. is there a sample script I can follow?

JQ1982 gravatar imageJQ1982 ( 2018-01-04 08:03:53 -0500 )edit

Also, node definitions (in site.pp or similar) can use regular expressions, so you may be able to avoid implementing an ENC by having something like node /web\d+/ { include role::web_server } https://puppet.com/docs/puppet/5.3/lang_node_definitions.html#regular-expression-names

gabe_sky gravatar imagegabe_sky ( 2018-01-11 13:00:10 -0500 )edit

answered 2018-01-03 12:52:21 -0500

JQ1982 gravatar image

updated 2018-01-09 13:32:03 -0500

DarylW gravatar image

Is there a way to pass a variable or parameter with the line below? Or do I have to user the csr attributes?

Or do I hav to

curl -k https://puppet.localdomain:8140/packa... | sudo bash -s main:certname=${hostname}.localdomain main:server=puppet.localdomain customattributes:challengePassword=${puppetchallenge_password}

If I can pin with the above, I can passing a parameter, I can easily do this passing a variable in user data if I'm using AWS or pass a script when I'm building via kickstart.

edit flag offensive delete link more


Hi, instead of posting this followup question as an 'answer' it would be better if you edited your original question.

Martijn Heemels gravatar imageMartijn Heemels ( 2018-01-12 04:30:26 -0500 )edit

answered 2018-01-12 05:04:13 -0500

Martijn Heemels gravatar image

In our Puppet open source installation we assign roles based on a custom fact that is created on our EC2 instances via user-data (i.e. on first boot).

Here's an extract from the Cloud-Init script in the node's user-data:

  - path: /etc/puppetlabs/facter/facts.d/role.txt
    content: role=lamp_server
  - path: /etc/puppetlabs/facter/facts.d/tier.txt
    content: tier=production

Our hiera.yaml then maps the role fact to a Hiera yaml file:

version: 5
defaults:  # Used for any hierarchy level that omits these keys.
  datadir: hieradata         # This path is relative to hiera.yaml's directory.
  data_hash: yaml_data  # Use the built-in YAML backend.

  - name: "Per-node data"
    path: "node/%{facts.fqdn}.yaml"

  - name: "Per-tier data"
    path: "tier/%{facts.tier}.yaml"

  - name: "Per-role data"
    path: "role/%{facts.role}.yaml"

  - name: "Common data"
    path: "common.yaml"

Then in (for example) hieradata/role/lamp_server.yaml we assign an actual class to the node.

  - roles::lamp_server

Which we include via the following line in site.pp

hiera_include('classes') | $key | {"No 'role' found"}
edit flag offensive delete link more

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower


Asked: 2018-01-02 10:57:34 -0500

Seen: 231 times

Last updated: Jan 15