puppethiera

How to realize virtual hiera data in puppet, or, how to abstract hiera user definitions from user selection on each machine?


I am trying to define virtual user & group data in hiera, and then realize it only on the nodes where it's needed, by defining user lists and group lists on a per-host basis. Note: I am using the accounts module from puppet forge, and it utilizes the accounts:: name space in hiera. For example, just as a baseline for something that works, if I create this:

# snippet from hiera.yaml
hierarchy:
  - name: "Users and Groups"
    glob: "UsersAndGroups/*.yaml"

and

# snippet from data/UsersAndGroups/webadmins.yaml
accounts::user_list:
  alice:
    uid: '999'
    gid: '999'
    comment: 'Alice User'
    shell: '/bin/bash'
  bob:
    uid: '998'
    gid: '998'
    comment: 'Bob User'
    shell: '/bin/bash'

It works, but the problem is, alice and bob get created on all machines. I only want them to be created on some. I would like to instead, define this data in hiera as virtual and then use a different data structure to specify which resources should be realized on each machine, for example:

# snippet from data/UsersAndGroups/webadmins.yaml
accounts::user_list:
  @alice:
    uid: '999'
    gid: '999'
    comment: 'Alice User'
    shell: '/bin/bash'
  @bob:
    uid: '998'
    gid: '998'
    comment: 'Bob User'
    shell: '/bin/bash'

and then create another data structure (and corresponding puppet class, not shown), like so:

# snippet from data/users_by_host/hosts.yaml
realize_accounts::by_host:
  host1.example.dom:
    - alice
    - bob
  host2.example.dom:
    - bob
  host3.example.dom:
    - alice

I've tried every variation I can think of to make this work, but have failed so far. The first problem is the virtual resource declaration. It doesn't like me using the @ symbol. I receive the error message: found character '@' that cannot start any token.

Can anyone suggest how to abstract the user definitions from the selection of which users should be created on which machines?


Solution

  • I am trying to define virtual user & group data in hiera, and then realize it only on the nodes where it's needed, by defining user lists and group lists on a per-host basis.

    Ok, that's not unreasonable.

    Note: I am using the accounts module from puppet forge, and it utilizes the accounts:: name space in hiera.

    You can use the puppetlabs/accounts module, but you cannot use its accounts class to manage users or groups if you want to stick to your plan, because it does not provide for declaring those virtually. That is a function of the Puppet code of the declarations, not (directly) of any data the class consumes.

    You can still use the Accounts::User defined type, the module's various custom data types, and its custom functions. These perhaps provide enough of a value-add relative to Puppet's core User resource type to make the module worth it. You're probably looking at the core Group resource type in any case. You would need to declare Accounts::User (or User) and Group resources virtually, and then realize the wanted ones based on your per-host lists.


    But there are other alternatives. You clarified in comments that your objective is to centralize master lists of user and group properties, from which you can select subsets on a per-machine basis. You can do all of that directly in Hiera with the help of Hiera's alias() interpolation function.

    You would do this with a two- (at least) level hierarchy. The user and group details would go into an hierarchy level shared by all hosts, and perhaps accounts::user_defaults and accounts::group_defaults would go there too, if you use them. The accounts::user_list and accounts::group_list would go in a per-host or an otherwise more specific hierarchy level, interpolating elements from the central list. Example:

    common.yaml

    user:
      alice:
        uid: '999'
        gid: '999'
        comment: 'Alice User'
        shell: '/bin/bash'
      bob:
        uid: '998'
        gid: '998'
        comment: 'Bob User'
        shell: '/bin/bash'
    

    host1.yaml

    accounts::user_list:
      alice: "%{alias('user.alice')}"
      bob: "%{alias('user.bob')}"
    

    host2.yaml

    accounts::user_list:
      bob: "%{alias('user.bob')}"
    

    host3.yaml

    accounts::user_list:
      alice: "%{alias('user.alice')}"