4

Is there any way to declare in Puppet's language that packages in an array should installed in the order they are given in the array?

I want to automate the installation of CUDA, which requires nvidia-driver-latest-dkms, cuda and cuda-drivers (on RHEL7 as an example) to be installed in that order. I do not want to hard-code the array of packages, because I need to support different distributions, which require different packages. Therefore, an array holding the packages provided via Hiera seemed to be a good idea.

My first solution was ensure_packages($packages_parameter_filled_via_hiera), which stopped working recently (probably due to changes in NVIDIA's packages). The problem seems to be that this code installs the packages in a random order, and you cannot install nvidia-driver-latest-dkms (any more) if any of the other packages is already installed.

My next approach,

$packages.each | $package | {
    ensure_packages($package)
}

has the very same problem as does

$packages.each | $package | {
    package { "cuda-${package}":
        name => $package
    }
}

What I am looking for is something that is equivalent to the -> or ~> operator between the loop instances, or alternatively, some "dangling-pointer" construct that would give me access to the previous $package such that I can write require => Package[$magic_previous_instance] in the package resource. That is, I want to create something equivalent to

package { 'cuda-epel-release': 
    name => 'epel-release'
}
-> package { 'cuda-nvidia-driver-latest-dkms': 
    name => 'nvidia-driver-latest-dkms'
}
-> package { 'cuda-cuda': 
    name => 'cuda'
}
-> package { 'cuda-cuda-drivers': 
    name => 'cuda-drivers'
}

(which actually works, but exactly for RHEL 7) dynamically from Hiera data.

Christoph
  • 1,964
  • 2
  • 27
  • 44

1 Answers1

2

Yes, this is actually possible with a "wrapper" defined resource type:

define custom::install(Hash $pkg_hash) {
  # iterates through the packages in the hash using their keys, and creates a package default where each requires the previous package
  # index > 0 ensures the first package does not attempt to require a nonexistent previous package
  keys($pkg_hash).each |Integer $index, String $pkg| { if $index > 0 { Package[keys($pkg_hash)[$index - 1]] -> Package[$pkg] } }

  create_resources(package, $pkg_hash)
}

To give credit where credit is due, I was originally pointed in this direction by Henrik Lindberg, so it is not entirely my creation. The input Hash $pkg_hash for the defined resource type is a package hash type analogous to the input argument structure for the create_resources function second argument. For example:

$pkg_hash = {
  'cuda-epel-release'              => { ensure => installed },
  'cuda-nvidia-driver-latest-dkms' => { ensure => installed }
}

or in Hiera data YAML format:

pkg_hash:
  'cuda-epel-release':
    ensure: installed
  'cuda-nvidia-driver-latest-dkms':
    ensure: installed

and then custom::install($pkg_hash) as expected.

Note that create_resources in the DRT can be replaced as per normal:

$pkg_hash.each |String $package, Hash $attributes| {
  package { $package: *=> $attributes }
}

as described in the bottom of the documentation (Puppet doc quick link not working).

Matthew Schuchard
  • 25,172
  • 3
  • 47
  • 67