2

My first thought was doing something like this:

define my_user( $name = $title, $ensure = present, $uid, $gid, $password, $groups, $comment, $shell ) {
    $managehome = $ensure ? {
        present => true,
        default => false,
    }
    user { $name:
        ensure     => $ensure,
        managehome => $managehome,
        uid        => $uid,
        gid        => $gid,
        password   => $password,
        groups     => $groups,
        comment    => $comment,
        shell      => $shell,
     }
}

A couple of problems with this:

  • If I wanted to use another user type attribute, I'd need to change my_user in two places.
  • I would need to change all user declarations to use my_user.
  • I would much rather use a built-in type then a defined type.

Perhaps there's either:

  • A way to catch all parameters to a defined type and pass it in as attributes to a built-in type.
  • An even more elegant way to do this without using defined types.

Does anyone have any recommendations?

5

There are a few ways to handle this, you could simply use your ternary check directly in the user declaration like so:

user { $user:
  ensure     => $ensure,
  managehome => $ensure ? { present => true, default => false, },
  uid        => $uid,
  gid        => $gid,
  password   => $password,
  groups     => $groups,
  comment    => $comment,
  shell      => $shell,
}

This is assuming you are parameterizing your values here, and I'm guessing that's not necessarily the case. You would still have the issue of having to update all your type references which can be a bit painful. Instead, you could use something vastly more powerful, the create_resources function. Consider the following excerpt from a puppet file:

class profile::base {
  $user_params = {
      'user1'     => { ensure     => absent,
                       managehome => false,
                       uid        => '1337',
                       gid        => dev,
                     },
      'user2'     => { uid        => '1338',
                       gid        => ops,
                       groups     => ['wheel', 'company'],
                     },
  }

  $user_defaults = {
      ensure        => present,
      managehome    => true,
      groups        => ['users', 'company'],
      comment       => 'Managed by puppet',
      shell         => '/bin/bash',
  }

  create_resources(user, $user_params, $user_defaults)

  ...
}

So what ends up happening here, is that the create_resources function takes the hash $user_params and dynamically creates a resource for each entry using the paramaters supplied. Additionally, any parameters not supplied by $user_params use values from the $user_defaults hash. The above code effectively evaluates to the following snippet. (If you're unfamiliar with the create_resources function, I highly recommend reading about it here)

class profile::base {

  user { 'user1':
    ensure     => absent,
    managehome => false,
    uid        => 1337,
    gid        => dev,
    groups     => ['users', 'company'],
    comment    => 'Managed by puppet',
    shell      => '/bin/bash',
  }

  user { 'user2':
    ensure     => present,
    managehome => true,
    uid        => 1338,
    gid        => ops,
    groups     => ['wheel', 'company'],
    comment    => 'Managed by puppet',
    shell      => '/bin/bash',
  }

  ...
}

This allows you to quickly add/change attributes across all the users you want to manage without having to find every reference. Say if you want to switch to using ksh for your company you simply change the value in the user_defaults hash to reflect this. There's also nothing stopping you from having different groups of params and defaults (say $root_params and $root_defaults for your super users) and having another create_resources function call.

Taking this idea one step further, you can pair this concept with data from Hiera The solution would then look like this:

class profile::base {
  $user_params = hiera("user-params")
  $user_defaults = hiera("user-defaults")

  create_resources(user, $user_params, $user_defaults)

  ...
}

Much cleaner and easier to read. The corresponding hieradata json file would look like this:

{
  "user-params": {
                  "user1": {
                            "ensure": "absent",
                            "managehome": "false",
                            "uid": "1337",
                            "gid": "dev"
                  },

                  "user2": {
                            "uid": "1338",
                            "gid": "ops",
                            "groups": ["wheel", "company"]
                  }
  },

  "user_defaults": {
                    "ensure": "present",
                    "managehome": "true",
                    "groups": ["users", "company"],
                    "comment": "Managed by puppet",
                    "shell": "/bin/bash"
  }
}

I personally prefer JSON for my hieradata but YAML is also a viable option (Hiera Data Sources) The nice thing about Hiera is that you can use different data sources based on any criteria you decide and configured in the hiera.yaml file (typically done per environment, but could be per node)

As a final thought, you may want to consider writing a custom type to wrap the user type which would:

  • Archive a user's home directory if ensure => absent
  • Search for and restore an archived directory if ensure => present
  • Utilize the built-in user type normally with managehome => true

If you decide to take that route, you would still gain a lot of benefit through using the create_resources function and Hiera

| improve this answer | |
0

There's a less than elegant approach for optional parameters in this scenario.

my_user($ensure = 'present', $uid = undef) {
    if $uid != undef { User { uid => $uid } }
    user { $name: ensure => $ensure }
}

You just assign resource defaults for user in the scope of the define. You can repeat this pattern for an arbitrary number of parameters.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.