Search code examples
rubypuppetredhat

Puppet error Unknown variable: 'ssh_user' for custom resource type in a custom module


I am seeing the following error when my Puppet agent is attempting to retrieve the configuration from the Puppet Server (v8), all running on Redhat OS:

Error: Could not retrieve catalog from remote server: Error 500 on SERVER: Server Error: Evaluation Error: Unknown variable: 'ssh_user'

The error refers to a custom resource type defined in a module called "Users".

class users::virtual {

    define ssh_user( $user=$name, $uid, $password, $key, $home_dir = 'home' ) {
        user { $user:
            ensure     => present,
            managehome => true,
            uid        => $uid,
            password   => $password,
            home       => "/${home_dir}/${user}"
         }

        ssh_authorized_key { "${user}_key":
            key  => $key,
            type => "ssh-rsa",
            user => $user,
        }

    }

    define ssh_home ($home_dir = 'home') {
      file { "/${home_base_dir}/${name}/.ssh":
          ensure => directory,
          owner  => $name,
          group => $name,
          mode => 0700,
      } ->

      file { "/${home_dir}/${name}/.ssh/id_rsa":
          source => "puppet:///modules/users/${name}/ssh/id_rsa",
          owner  => $name,
          group => $name,
          mode => 0600,
      } ->

      file { "/${home_dir}/${name}/.ssh/id_rsa.pub":
          source => "puppet:///modules/users/${name}/ssh/id_rsa.pub",
          owner  => $name,
          group => $name,
          mode => 0644,
      }
    }
            
    ssh_user { "myuser":
        uid      => 1010,
        password => 'hidden',
        key      => "hidden",
    }

}

Any ideas why this is happening? I removed @ssh_user and tried $ssh_user but see the same error.


Solution

  • When you define a class or resource type inside the definition of a different one, it goes into the namespace defined by the container. So, with ...

    class users::virtual {
    
        define ssh_user( $user=$name, $uid, $password, $key, $home_dir = 'home' ) {
            user { $user:
                ensure     => present,
                managehome => true,
                uid        => $uid,
                password   => $password,
                home       => "/${home_dir}/${user}"
             }
    
            ssh_authorized_key { "${user}_key":
                key  => $key,
                type => "ssh-rsa",
                user => $user,
            }
    
        }
    

    ... the (fully-qualified) name of the defined type is users::virtual::ssh_user.

    In Puppet 3 and earlier, Puppet would attempt to resolve class and defined type names such as ssh_user relative to the innermost local namespace first, working its way outward until it found a namespace wherein the name was defined, or else did not find it even as a top-scope name. That behavior was dropped in Puppet 4. Since then, you always need to refer to classes and defined types by their fully-qualified names. This is one of the lesser of a number of reasons why you should not nest class and defined type definitions.

    The best solution, then, would be to lift the ssh_user type to its own file, presumably modules/users/manifests/ssh_user.pp. In that case, the name by which you reference it would be users::ssh_user:

        users::ssh_user { "myuser":
            uid      => 1010,
            password => 'hidden',
            key      => "hidden",
        }
    

    On the other hand, if you stick with the nested definition then you'll still need to refer to the type via its full name, but that name will be users::virtual::ssh_user, as already described:

        users::virtual::ssh_user { "myuser":
            uid      => 1010,
            password => 'hidden',
            key      => "hidden",
        }
    

    If you want keep the same fuilly-qualified name when you lift the type to its own file, then you can instead put it in modules/users/manifests/virtual/ssh_user.pp.

    Wherever you put the type, if you lift it into its own file then you should define it with its fully-qualified name. For example,

    modules/users/manifests/ssh_user.pp

    define users::ssh_user( $user=$name, $uid, $password, $key, $home_dir = 'home' ) {
      # ...
    }